home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / basic / qbnws202.zip / QBNWS202.NWS < prev    next >
Text File  |  1991-05-31  |  173KB  |  3,616 lines

  1.      Volume  2, Number  2                                      May 31, 1991
  2.  
  3.      
  4.      
  5.      
  6.      
  7.      
  8.      
  9.      
  10.      
  11.      
  12.      
  13.      
  14.      
  15.                    **************************************************
  16.                    *                                                *
  17.                    *                    QBNews                      *
  18.                    *                                                *
  19.                    *      International QuickBASIC Electronic       *
  20.                    *                  Newsleter                     *
  21.                    *                                                *
  22.                    *    Dedicated to promoting QuickBASIC around    *
  23.                    *                  the world                     *
  24.                    *                                                *
  25.                    **************************************************
  26.      
  27.      
  28.      
  29.      
  30.      
  31.      
  32.      
  33.      
  34.      
  35.      
  36.      
  37.      
  38.      
  39.      
  40.      
  41.      
  42.         The  QBNews  is  an electronic newsletter  published  by  Clearware
  43.      Computing. It can be freely distributed providing NO CHARGE is charged
  44.      for  distribution.  The  QBNews is copyrighted in  full  by  Clearware
  45.      Computing.  The  authors  hold  the  copyright  to  their   individual
  46.      articles.  All program code appearing in QBNews is released  into  the
  47.      public  domain.   You  may  do what you  wish  with  the  code  except
  48.      copyright  it.  QBNews  must  be  distributed  whole  and  unmodified.
  49.      
  50.      You can write The QBNews at:
  51.      
  52.           The QBNews
  53.           P.O. Box 507
  54.           Sandy Hook, CT 06482
  55.      
  56.      Copyright (c) 1991 by Clearware Computing.
  57.      
  58.      The QBNews                                                   Page    i
  59.      Volume  2, Number  2                                      May 31, 1991
  60.  
  61.      
  62.  
  63.      ----------------------------------------------------------------------
  64.  
  65.                         T A B L E   O F   C O N T E N T S
  66.  
  67.      
  68.      1.  From the Editor's Desk
  69.           Exciting New Things Happening with BASIC .....................  1
  70.  
  71.      2.  Ask The Doctor
  72.           How to Copy Files with QuickBASIC ............................  2
  73.  
  74.      3.  Advertisement
  75.           PDQComm - Professional Communications for "Power Programmers"   5
  76.  
  77.      4.  View Print
  78.           BASICZen by John Richard De Palma ............................  6
  79.  
  80.      5.  Swap Shop
  81.           Create Bar Charts in Text Mode with QB by David Rice ......... 12
  82.           Create Pie Charts with QB by David Rice ...................... 16
  83.           Add BASIC 7's DIR$ Routine to your QB Programs by Dave Cleary  20
  84.  
  85.      6.  The Tool Shed
  86.           A Look at Crescent Software's PDQComm by Jim Harre ........... 22
  87.  
  88.      7.  Who ya gonna call? CALL INTERRUPT
  89.           Working with the Rodent by Daniel R. Berry ................... 27
  90.           A Graphics Mouse Cursor Design System by Warren G. Lieuallen . 32
  91.  
  92.      8.  The QBNews Professional Library
  93.           Fast Screen Printing by Christy Gemmel ....................... 34
  94.           ROM-BIOS Video Services ...................................... 48
  95.           Using FastPrint with BASIC 7 ................................. 49
  96.  
  97.      9.  Power Programming
  98.           An Improved Cloning Algorithm by Larry Stone ................. 51
  99.  
  100.      10.  New and Noteworthy
  101.           Custom Control Factory for Microsoft Visual Basic by Desaware  53
  102.  
  103.      11.  Fun and Games
  104.           ASCII Art -- A Piece of Computer History by Charles Graham ... 54
  105.  
  106.      12.  QBNews Special Report
  107.           Special Preview of Visual Basic by Dave Cleary ............... 57
  108.  
  109.      13.  EOF
  110.           Receiving The QBNews ......................................... 59
  111.           Submitting Articles to The QBNews ............................ 60
  112.  
  113.      
  114.      
  115.      
  116.      
  117.      The QBNews                                                   Page   ii
  118.      Volume  2, Number  2                                      May 31, 1991
  119.  
  120.  
  121.  
  122.      ----------------------------------------------------------------------
  123.                    F r o m   t h e   E d i t o r ' s   D e s k
  124.      ----------------------------------------------------------------------
  125.  
  126.      Exciting New Things Happening with BASIC
  127.      
  128.         Since the last QBNews, quite a bunch of exciting new things has
  129.      been happening with our favorite language. First and foremost,
  130.      Microsoft has finally released Visual Basic, its Windows Basic
  131.      programming environment. Also, BASICPro, a new magazine devoted to
  132.      BASIC programmers has been started. Finally, Microsoft is holding
  133.      a big developers conference for BASIC programmers in Washington at
  134.      the end of August. We will be able to meet the developers of
  135.      Microsoft's BASIC products and even Mr. Bill himself. I hope to see
  136.      some of you readers up there.
  137.      
  138.         This newsletter will be remain devoted to QuickBASIC programming.
  139.      However, the next two issues will be covering Visual Basic as this
  140.      is a very exciting new product. There is a VB preview in this issue
  141.      and I hope for more in depth stuff for VB and other Windows BASIC
  142.      environments for the next issue.
  143.      
  144.         BASICPro magazine is now two issues old. Although a bit pricey,
  145.      the magazine holds much promise to become the Dr. Dobbs of QuickBASIC.
  146.      If you haven't seen BASICPro, give them a call at 415-688-1808 to
  147.      order a trial subscription. Don't forget to tell them you heard of
  148.      BASICPro through The QBNews.
  149.      
  150.         Finally, I am kicking off a new series of articles for The QBNews.
  151.      It is called The QBNews Professional Library. I am putting together
  152.      an assembly language library written by the industries top
  153.      programmers. Not only will you get ASM source code of the routines
  154.      contained in the library, but you will get an in depth article
  155.      explaining what is going on. This series should help people understand
  156.      the bits and bytes that make our computers tick and help make them
  157.      into better programmers.
  158.      
  159.      Dave Cleary - Publisher of The QBNews
  160.      
  161.  
  162.  
  163.  
  164.  
  165.  
  166.  
  167.  
  168.  
  169.  
  170.  
  171.  
  172.  
  173.  
  174.  
  175.  
  176.      The QBNews                                                     Page  1
  177.      Volume  2, Number  2                                      May 31, 1991
  178.  
  179.  
  180.  
  181.      ----------------------------------------------------------------------
  182.                            A s k   T h e   D o c t o r
  183.      ----------------------------------------------------------------------
  184.  
  185.      Ask The Doctor
  186.      
  187.         Ask The Doctor is a new question and answer area for The QBNews.
  188.      You send in your questions and I will try my best to either answer
  189.      them myself or get one of the many QB experts I know to answer them
  190.      for me. If your question is used, I will send you that issue of The
  191.      QBNews on disk as soon as it is published. Because I am not superman,
  192.      I will not be able to answer every ones questions so if you don't see
  193.      your question in the QBNews, don't expect a reply. Of course, you can
  194.      always call the Crescent Software Support BBS to leave me questions
  195.      that I will try to answer. That number is 203-426-5958.
  196.         
  197.      
  198.      Dear Dave:
  199.      
  200.         Keep the QBNews coming.  I have been doing simple programming in
  201.      QuickBasic for over a year now but have not been able to progress very
  202.      far.  Your electronic magazine has been extremely helpful. Here is a
  203.      question you or one of your contributors might be able to help me
  204.      with.  I am wanting to copy or move files around on my hard drive.  I
  205.      do not want to shell to dos and use the copy command.  How can I do
  206.      this using QB?  I have been reading the disk I/O section of my QB
  207.      manual but it is not very clear about how I might go about copying or
  208.      moving files.  I have look at some dos interrupt functions in a book
  209.      call, "Programmer's Guide to the IBM PC".  But again I am not sure how
  210.      to go about using interrupts to copy or move files around.
  211.      
  212.      Is there any help out there for a novice like me?
  213.      
  214.      Thanks,
  215.      Steven E. Walker
  216.      Wilkinson, IN
  217.      
  218.      Steven,
  219.      
  220.         QuickBASIC has many different ways to read an write files. This may
  221.      have caused your confusion. Copying files is easily done in QuickBASIC
  222.      and is quite fast also.
  223.      
  224.         Lets first look at the options QB gives us to read a file. The
  225.      three major commands to read a file are LINE INPUT, INPUT$, and GET.
  226.      LINE INPUT is only good for text files and is also one of the slowest
  227.      QB commands as far as file IO goes. That leaves INPUT$ and GET.
  228.      
  229.         GET and PUT are by far the fastest IO commands QB has. This is
  230.      because with GET, the area of memory where the data gets placed is
  231.      already allocated. All QB has to do is set up some registers and then
  232.      call DOS to read the file.
  233.      
  234.         INPUT$ is another command that works for both text and binary
  235.      
  236.      The QBNews                                                     Page  2
  237.      Volume  2, Number  2                                      May 31, 1991
  238.  
  239.      files. INPUT$ is slightly slower than the GET command because it
  240.      allocates memory to hold the data each time it is called. I have found
  241.      this speed difference to be inconsequential though. INPUT$ does offer
  242.      some advantages over GET in our CopyFile routine. When you are at the
  243.      end of a file, INPUT$ will return a string with the exact number of
  244.      bytes left in the file even if you asked for more. This relieves us of
  245.      knowing the size of the file we are working with. GET, on the other
  246.      hand, will pad your buffer with null characters, causing us to have to
  247.      truncate the last read if we want to keep our file lengths the same.
  248.      For this reason, I chose INPUT$ over GET to read in the file.
  249.      
  250.      So here is our copy file routine:
  251.      
  252.      DEFINT A-Z 
  253.      
  254.      DECLARE FUNCTION DIR$ (FileSpec$)      'Comment out if using BASIC 7
  255.      DECLARE FUNCTION CopyFile% (Source$, Dest$)
  256.      
  257.      '$INCLUDE: 'QB.BI'                     'Required for CALL INTERRUPT
  258.      
  259.      CONST Block = 4096                     'Set this to the length you
  260.                                             'want your buffer to be
  261.      
  262.      'Example of how to call CopyFile
  263.      'Ercd = CopyFile("D:\PDQ\HISTORY.DOC", "C:\SCRAP\TEST1")
  264.      
  265.      FUNCTION CopyFile% (Source$, Dest$) STATIC 
  266.      
  267.      DIM Regs AS RegType                    'Needed for CALL INTERRUPT
  268.      
  269.      '-----  See if source file exists
  270.      IF LEN(DIR$(Source$)) = 0 THEN         'Use DIR$ function from this
  271.                                             'issues SwapShop if you are
  272.                                             'using QB 4.x.
  273.         CopyFile% = 1                       'Source doesn't exist 
  274.         EXIT FUNCTION                       'Exit with error code
  275.      END IF
  276.      
  277.      '-----  See if destination exists
  278.      IF LEN(DIR$(Dest$)) THEN
  279.         CopyFile% = 2                       'Destination already exists 
  280.         EXIT FUNCTION                       'Exit with error code
  281.      END IF
  282.      
  283.      '-----  Open files for BINARY
  284.      SFileNum = FREEFILE
  285.      OPEN Source$ FORBINARY AS #SFileNum
  286.      
  287.      DFileNum = FREEFILE
  288.      OPEN Dest$ FOR BINARY AS #DFileNum
  289.      
  290.      '-----  Now copy the files over
  291.      DO
  292.         Buffer$ = INPUT$(Block, #SFileNum) 
  293.      
  294.      The QBNews                                                     Page  3
  295.      Volume  2, Number  2                                      May 31, 1991
  296.  
  297.         PUT #DFileNum, , Buffer$
  298.      LOOP UNTIL EOF(SFileNum)
  299.      
  300.      '-----  Set the date and time of the copy to that of the original
  301.      Regs.ax = &H5700
  302.      Regs.bx = FILEATTR(SFileNum, 2)        'This gets DOS's file handle
  303.      INTERRUPT &H21, Regs, Regs             'Get date and time of original
  304.      
  305.      '-----  Check for an error
  306.      IF (Regs.flags AND 1) THEN
  307.         CLOSE #SFileNum, #DFileNum          'Close the files 
  308.         KILL Dest$                         'Kill our copy because something 
  309.         CopyFile% = 3                       'went wrong. Exit with error 
  310.         EXIT FUNCTION
  311.      END IF
  312.      
  313.      Regs.ax = &H5701
  314.      Regs.bx = FILEATTR(DFileNum, 2)
  315.      INTERRUPT &H21, Regs, Regs             'Set date and time of copy
  316.      
  317.      '-----  Check for an error
  318.      IF (Regs.flags AND 1) THEN
  319.         CLOSE #SFileNum, #DFileNum          'Close the files 
  320.         KILL Dest$                         'Kill our copy because something 
  321.         CopyFile% = 3                       'went wrong. Exit with error 
  322.         EXIT FUNCTION
  323.      END IF
  324.      
  325.      CLOSE #SFileNum, #DFileNum             'All done
  326.      CopyFile% = 0                          'Return with success
  327.      
  328.      END FUNCTION
  329.      
  330.      
  331.         This routine returns a 0 if everything went all right. It will
  332.      return a 1 if the source file doesn't exist and a 2 if the destination
  333.      file does exist. It will return a 3 if something went wrong in setting
  334.      the copy's date and time to that of the original. This routine uses
  335.      BASIC 7 PDS DIR$ function. For those of you with QuickBASIC, I have
  336.      written a DIR$ function for you that appears in this issues SwapShop
  337.      section. The DIR$ I wrote works in much the same way that BASIC 7's
  338.      does.
  339.      
  340.      If you have a question for the Doctor, please send them to:
  341.      
  342.         Ask The Doctor
  343.         P.O. Box 507
  344.         Sandy Hook, CT 06482
  345.      
  346.  
  347.  
  348.  
  349.  
  350.  
  351.      The QBNews                                                     Page  4
  352.      Volume  2, Number  2                                      May 31, 1991
  353.  
  354.  
  355.  
  356.      ----------------------------------------------------------------------
  357.                             A d v e r t i s e m e n t
  358.      ----------------------------------------------------------------------
  359.  
  360.      PDQComm - Professional Communications for "Power Programmers"
  361.      
  362.      PDQComm contains both low-level and high-level routines that add
  363.      advanced communications capabilities to programs written using
  364.      Microsoft QuickBASIC version 4.0 or later, and BASIC 7 PDS.  PDQComm
  365.      was originally designed to be used with our P.D.Q. replacement link
  366.      library, however, PDQComm is also ideal for use with regular BASIC
  367.      programs.
  368.                  ***** PDQComm is small and fast *****
  369.      All of the routines provided with PDQComm are extremely small, and
  370.      thus add very little code to your programs.  The core routines for
  371.      creating a complete terminal program add less than 2500 bytes.
  372.      Compare that to the more than 12K which QuickBASIC adds, or perhaps
  373.      more important, to other communications libraries that are available!  
  374.                  ***** PDQComm is easy to use *****
  375.      All of the PDQComm routines have been designed to emulate the syntax
  376.      of the QuickBASIC routines they replace as closely as possible.
  377.      PDQComm also takes advantage of the features available in QuickBASIC
  378.      4.0 and later. For example, to get a string of characters from the com
  379.      port, you would do the following: 
  380.      
  381.      QuickBASIC:                         PDQComm:
  382.      Work$ = INPUT$(LOC(1), #1)          Work$ = ComInput$(ComLoc) 
  383.      
  384.      Compare that to what other communications libraries make you do: 
  385.      CALL MhGetRecvStatus(Port, CharsInBuffer, ECode)
  386.      Work$ = SPACE$(100 + CharsInBuffer * 2)
  387.      CALL MhGetData(Port, Work$, Length, ECode)
  388.      Work$ = LEFT$(Work$, Length)
  389.         ***** PDQComm supports high speed communications *****
  390.      While most communications libraries claim to support baud rates up to
  391.      115k, a standard serial port has problems keeping up. To insure error
  392.      free high-speed communications, PDQComm supports the NS16550A UART.
  393.      This is an advanced IC that contains an on chip buffer, allowing the
  394.      PC more time to receive incoming characters.
  395.         ***** PDQComm comes with many bells and whistles *****
  396.      Also included is full emulation for the ANSI, DEC VT52 and VT100, Data
  397.      General D215, and generic terminal standards. These emulations can be
  398.      instructed to operate within a windowed area, and you can even have
  399.      multiple windows active at one time.  PDQComm also comes with XModem
  400.      and ASCII file transfer routines. The PDQComm manual contains
  401.      extensive tutorial information explaining modems, serial cables,
  402.      specifying port parameters, and UARTs.  All of the important Hayes
  403.      commands are described in detail, and each emulation includes a table
  404.      of codes that are recognized. PDQComm costs $99. For more information
  405.      or to order PDQComm, please call Crescent Software.
  406.      
  407.      Crescent Software - Orders:800-35-BASIC - Tech Supt:203-438-5300
  408.      Crescent Software Support BBS:203-426-5958 - 2400,N,8,1
  409.      
  410.      The QBNews                                                     Page  5
  411.      Volume  2, Number  2                                      May 31, 1991
  412.  
  413.  
  414.  
  415.      ----------------------------------------------------------------------
  416.                                V i e w   P r i n t
  417.      ----------------------------------------------------------------------
  418.  
  419.      BASICZen by John Richard De Palma
  420.      
  421.           Red haired Sandra  is  the  manager  of  the  local  Egghead
  422.      Software store.  Gazing at  her collection  of software  I  said,
  423.      "Hi Sandra, Uh... can you  show me  what books  and  software you
  424.      have on learning to program in BASIC?"
  425.      
  426.           "No, no...NOOOO... John, you want this!" Sandra said, as she
  427.      thrust an  orange 10  pound box of manuals and disks into my arms
  428.      and gave me a beaming smile.
  429.      
  430.           She went  on, "I  studied Pascal  and "C" in college for TWO
  431.      years, no  one, and  I mean  no one studies BASIC anymore, it's a
  432.      dead programming  language."   She  laughed,  "Just  as  dead  as
  433.      learning Latin."
  434.      
  435.           "Well, Uh,"  I shifted  my feet  for better  support and put
  436.      down Borland's  version of Turbo Pascal, "I studied Latin for two
  437.      years, and  it's not  all that  dead," .  "You see, Latin teaches
  438.      you to  know intuitively many English prefixes, suffixes and many
  439.      of the  Romance language  verbs and  nouns...."  my voice trailed
  440.      off, even  to me  that sounded  like an  apology for spending two
  441.      years learning about BIG Julie and wars fought with catapults and
  442.      giant slingshots.
  443.      
  444.           "Oh, don't  be SILLY," Sandra said, "Here, if you don't like
  445.      that, buy this, its C ++ with OOP."
  446.      
  447.           "I'm not  even going to ask what "OOP" is, I said, just sell
  448.      me something in BASIC,"  I sighed.
  449.      
  450.           "What KIND  of basic programming do you want?"  Sandra asked
  451.      briskly,  swivelling   around  to  check  on  her  employees  and
  452.      motioning to Brian to stop playing with the joystick and get back
  453.      to work.
  454.      
  455.           "Well, hell,  I DON'T KNOW, I just want to learn how to make
  456.      my own programs like Paul Somerson does.  If BASIC is good enough
  457.      for him, it's good enough for me," my voice rising a half-octave.
  458.      I started  looking around  for the  IBM utilities  section in the
  459.      hopes of finding some box with basic BASIC information on it.
  460.      
  461.           There was no question that I knew NOTHING about programming.
  462.      I was  awkward and  out of  my  depth.    I  knew  nothing  about
  463.      programming except  that it  had to  be better  than using  batch
  464.      files to do things with MS-DOS.  I was going to tell Sandra about
  465.      batch files.   Tell  her about all the batch file programs that I
  466.      had looked  at that promised much and delivered little.  I wanted
  467.      to tell  her about batch techniques that did not allow input into
  468.      them except  as parameters  on the  command line  or by using the
  469.      
  470.      The QBNews                                                     Page  6
  471.      Volume  2, Number  2                                      May 31, 1991
  472.  
  473.      dopey "FOR"  command or  the klutzy  "IF ERRORLEVEL"  command.  I
  474.      wanted to  tell her  I  wanted  to  make  colorful  screens  with
  475.      selections that could be input by cursor control.  I wanted to be
  476.      able  to  change  directories,  do  file  sorts...  I  wanted  to
  477.      understand how  the computer  worked and then tell it what to do.
  478.      Hell and again hell, I wanted to control the computer software.
  479.      
  480.           Who's  Paul  Somerson?"  Sandra  queried.    "Some  computer
  481.      propeller head in Santa Monica?"
  482.      
  483.           "Gad, Sandy,  give me  a break!  Paul Somerson is the editor
  484.      of my favorite PC bible, "DOS Power Tools," he programs in BASIC.
  485.      Look...look, you  have his  book on  your bookshelf  right  here.
  486.      Wait... waaait,  I'll find  the section and read it to you.  Come
  487.      back here,  Oh let  Brian wait on that guy, this will only take a
  488.      minute."
  489.      
  490.           I picked  up the  book, found the page and read from my hero
  491.      Paul[1],
  492.      
  493.            "One  of the  nicest things  about BASIC  is  that  if  you
  494.      suddenly find  yourself with  a problem BASIC can tackle, you can
  495.      load it,  stumble your  way through  a program  and emerge with a
  496.      solution a  few minutes  later.  So maybe your program wasn't the
  497.      most elegant display of programming virtuosity; who cares as long
  498.      as it worked?"
  499.      
  500.           Sandra went on, "Well shoot yourself...I mean suit yourself,
  501.      heh, heh,  a little  joke there.   BASIC is dumb and slow.  Learn
  502.      "C" or  Pascal, I  did when  I went to UCLA.  No one teaches that
  503.      dumb stuff."  Sandra was very convincing and convinced.
  504.      
  505.           Backed into  a corner  and now  defending both Latin, a dead
  506.      language and BASIC a dead programming language I asked, "Well, if
  507.      that's true,  let me ask you a couple of questions.  Do you use a
  508.      computer...?   You do.  Do you use a computer to do applications,
  509.      spreadsheets and  mathematics...?  You do.  Do you use ANY of the
  510.      Pascal and "C" you learned to help you to doing things with these
  511.      programs.  You don't..?   Why?"
  512.      
  513.           Sandra went  on to  tell me how hard it was to keep up these
  514.      great skills  she learned  in college  and that she really didn't
  515.      have the  time to  program, or the interest.  She freely admitted
  516.      that though she studied programming for two years, she never used
  517.      it outside  of class.   She  glanced at  the clock,  at the three
  518.      people questioning  Brian all at the same time and gave me a book
  519.      called "Learn  BASIC Now."   She said as she walked away, "BASIC,
  520.      is too  dumb, it's  a wimpy  language.  You're wasting your time,
  521.      you'll be sorry.  It's really not even a HIGH language."
  522.      
  523.           Apparently I  bought a  peasant computer language of limited
  524.      capacity for  limited minds.   If  I wanted  to be  part  of  the
  525.      intelligentsia, I  should program in "C".  At least in "C" if not
  526.      in C ++  with OOP  or in  Pascal.   So I  went home,  loaded  the
  527.      
  528.      The QBNews                                                     Page  7
  529.      Volume  2, Number  2                                      May 31, 1991
  530.  
  531.      software and  wrote my first BASIC program with Microsoft's Quick
  532.      Basic 4.5  Interpreter.   The program  was one line of text which
  533.      printed to  the screen.  Big deal, I want power and I get a batch
  534.      file look alike.
  535.      
  536.           If I  couldn't learn  BASIC how  could I  learn  these  more
  537.      elitist and  complicated  computer  languages?    I  needed  some
  538.      verification and  clarification.  I began asking my friends about
  539.      computer programming.
  540.      
  541.           Harry said,  "Gosh John,  I learned FORTRAN and COBOL when I
  542.      was 17,  wrote flocks of programs in them, nope don't know BASIC,
  543.      it's too  dumb and slow.  What's that...do I ever USE FORTRAN and
  544.      COBOL?   No, not in years.  What good was learning it then?  What
  545.      the !@#$%*!, kind of question is that!"
  546.      
  547.           Harry is  always a  little sensitive  if you  imply that  he
  548.      might be bragging.  Harry is a card carrying elitist, he wouldn't
  549.      be caught dead using  such a  peasant computer language as BASIC.
  550.      
  551.           Ray is  different.   Ray owns  his own manufacturing company
  552.      and has  three Phd.s',  a law  degree, and went to medical school
  553.      for three  years.  "Of course I can program in BASIC, John, don't
  554.      be silly, that's child's play.  But don't get too technical, it's
  555.      been several years now, Hee Hee..., Ray chuckled.
  556.      
  557.           "Well Ray,  that's great,  I'm having a dickens of a time, I
  558.      didn't realize  that there  was BASIC,  BASICA, GWBASIC, PDB, and
  559.      QUICK BASIC.   What  do all  of these  names mean and which BASIC
  560.      should I learn?" I asked naively.
  561.      
  562.           Ray sputtered  a fine spray just as he was tasting the wine.
  563.      He ordered  another bottle  of Petite  Sirah; and we were able to
  564.      finish dinner  with that question hanging like still smoke in the
  565.      air.
  566.      
  567.           So it went on, if they did program "in the higher languages"
  568.      of C,  C +,  Pascal they  couldn't tell what and how they did the
  569.      programming.
  570.      
  571.           "Well John  why do  you REALLY want to learn to program for,
  572.      comm' on,  tell me....comm'  on...tell the truth,"  Marvin asked.
  573.      Marvin  programs   in  "C"   and  does   programs  in  artificial
  574.      intelligence   and    makes   jokes    about   "the    artificial
  575.      intelligentsia."
  576.      
  577.           In desperation,  I asked  Marvin to  write me a program that
  578.      could be  an all  purpose tool,  sort of  a Swiss Army knife that
  579.      would put  up menus, take direct input from the keyboard, let you
  580.      pick your  colors, be user friendly, be modifiable, you know like
  581.      software should be.  Marvin said that I didn't really know what I
  582.      wanted or, I wanted too much.  Besides nobody programs in BASIC.
  583.      
  584.           So I  went home  and dragged out QUICK BASIC again and tried
  585.      
  586.      The QBNews                                                     Page  8
  587.      Volume  2, Number  2                                      May 31, 1991
  588.  
  589.      halfheartedly to  learn something  that no  one knew  about  from
  590.      books written  by REAL  "propeller heads."  I read and reread the
  591.      texts trying  to UNDERSTAND  what  the  writer  was  driving  at.
  592.      Unfortunately BASIC  is mainly  written by  programmers  who  can
  593.      write code but who can't write to communicate with humans.
  594.      
  595.           It was a sort of Zen, reading and not understanding.  It was
  596.      a sort  of chant.   Reading again and again such stuff as: "DATE$
  597.      Statement sets  the current  date," and "DATE$ Function returns a
  598.      string containing  the current  date,"  and  "FUNCTION  Statement
  599.      Declares the name, parameters, and the code that form the body of
  600.      a FUNCTION procedure.[2]" Well that  is as clear as Zen, and like
  601.      Zen you  have to  have a  FEEL for  the terms.  As any Zen master
  602.      will tell you once you have the answer to the question, you DON'T
  603.      have the answer.
  604.      
  605.           QUICK BASIC  is  Zen,  a doing  without knowing.    But    I
  606.      followed the  instructions ---cook  book style---  and a  program
  607.      could be  made to  do something.   The sound of one hand clapping
  608.      makes sense now.  Trying to understand what is the meaning of the
  609.      phrase, "What  is the  sound of  one hand  clapping?" is  no more
  610.      difficult than trying to understand books written by programmers.
  611.      
  612.           I would  have given up too, except I was given a QUICK BASIC
  613.      program that  did something  that I  needed to  have done.   Pete
  614.      programs in QUICK BASIC.  Pete is probably the only person I know
  615.      that REALLY  programs anything  for himself  and  he  uses  QUICK
  616.      BASIC.   We have  a mutual  interest and  problem with  some data
  617.      collection and  analysis.   Pete had an answer to the problem and
  618.      he had  a real  program that  would give an answer all written in
  619.      QUICK BASIC.
  620.      
  621.           "Now Pete,  I WON'T  steal this program.  Also, I won't sell
  622.      this program  and make  a million dollars on it (Well... at least
  623.      not without  giving you HALF).  Yes, I promise, yes that's right,
  624.      cross my  heart and  hope to  die.   And I  won't give  it to the
  625.      Iraqis!  Now will you please...please....PLEASE give me a copy to
  626.      take home?"
  627.      
  628.           After whining  and pleading  that I would not sell his first
  629.      born program  into slavery  or copyright  it, he  gave me a copy.
  630.      That is  another Zen portion of programming, you have to earn the
  631.      knowledge yourself,  no one  can  do  it  for  you.    Only  with
  632.      programmers it's  worse than  Zen, they  won't give you a copy of
  633.      what they  know!   I watched him pull up the file, run it through
  634.      his compiler and give me code that would run by its self.  It was
  635.      like watching someone start a fire by using an ancient ritual, by
  636.      using a  bow and  a stick.   It was the dawn of civilization, the
  637.      passing of  knowledge, the  starting of  fire by friction.  I was
  638.      given a  real stand-alone  executable program  written by  a real
  639.      person, Wow!   After  more whining  he capitulated completely and
  640.      gave me the SECOND file, the QUICK BASIC code file.
  641.      
  642.           I put  the diskette in my shirt pocket, it was too important
  643.      
  644.      The QBNews                                                     Page  9
  645.      Volume  2, Number  2                                      May 31, 1991
  646.  
  647.      to place  it anywhere's  else.   That night I ran it inside of my
  648.      QUICK BASIC  compiler.   Gadsooks! it  worked!   The  damn  thing
  649.      calculated and printed the results out lightening fast and it was
  650.      information that I could really use.
  651.      
  652.           Zen, part  two, you  can't learn  something you  have no use
  653.      for.   That's what  Sandra, Harry,  Ray and  all the  others were
  654.      talking about.   They  wrote programs  in class  on problems that
  655.      they were  given, not  on  problems  they  wanted  solutions  for
  656.      themselves.   That's why  learning programming is like Zen, it is
  657.      meaningless unless  you have some use for the knowledge (which is
  658.      both very much like and UNLIKE Zen).
  659.      
  660.           Good ole Paul Somerson was right.  First, you need a project
  661.      that you  really...really want to do.  Then use the books to look
  662.      up the  procedures to do the project with.  Just learning all 190
  663.      QUICK BASIC commands won't cut it.  You have to use it ...or lose
  664.      it!
  665.      
  666.           I went  back to Egghead Software; Sandra and Brian had moved
  667.      on.  Scott and Lance programmed in Pascal.  I asked them if there
  668.      was anything  new in  QUICK BASIC  that was  fun.   Lance gave me
  669.      Microsoft's GAMESHOP.   It came with the same book that I already
  670.      had, but the software contained 6 games which could be run inside
  671.      of QUICK  BASIC, the  code could  be examined.   With  much  head
  672.      scratching and  replaying you  could actually  figure out how the
  673.      programmers did  what  they  did.    Again,  like  Zen  you  must
  674.      persevere, be  tested, try  and fail,  try  and  fail,  knowledge
  675.      doesn't come  easily.   But everyone  likes to  play games, so it
  676.      wasn't all Zen.
  677.      
  678.           That was  a month  ago, and though it is still slow going, I
  679.      am making  progress.   Pete and  GAMESHOP gave  me hope.   I have
  680.      uploaded two  programs to  CompuServe as  shareware.   The  first
  681.      program has  attracted two  dozen downloads  in two  weeks.   Not
  682.      great, but  a start and this is also Zen; you work and study long
  683.      for small  (or no)  rewards.  I guess some modem users downloaded
  684.      the program  because it  was simple, colorful, and played a song.
  685.      Nothing grand,  just a  program called  BIRTHDAY.ZIP that puts up
  686.      colored boxes on the screen, accepts user input, and plays "Happy
  687.      Birthday" if  the computer  clock reads the same day and month as
  688.      the ones  you type  in.   If it's  not your  birthday, it flashes
  689.      different colors and plays "Happy Unbirthday."
  690.      
  691.           Some one  laughed when  I played  the program  for them  and
  692.      jokingly asked  to see  it display  the EXACT age of anyone whose
  693.      birthday was  not the  day it  was run.  He also wanted something
  694.      that would distinguish if the person inputting the data was young
  695.      or old (over or under 21).
  696.      
  697.           That was  beyond my ability, but then I found, if you looked
  698.      hard enough,  someone had  already done  some of  these things in
  699.      QUICK BASIC  or BASICA.   I found a Julian (named after Big Julie
  700.      no less)  calendar function which does just that, and added it to
  701.      
  702.      The QBNews                                                     Page 10
  703.      Volume  2, Number  2                                      May 31, 1991
  704.  
  705.      the program.   After  struggling to add that formula, it was easy
  706.      to figure  out a  "LOOP" that  would change a phrase depending on
  707.      what the person's age was.  Though the latter was simple math, it
  708.      had been  years since  I had been forced to do any thinking about
  709.      mathematics.   Zen and  math have  a lot  in common,  but that is
  710.      another story.
  711.      
  712.           With a program that calculated the person's exact age, every
  713.      young woman  that played  the program  exclaimed "<Gasp>,  that's
  714.      wrong I  am NOT  29.078345 years old!" if that was her exact age.
  715.      I now  warn women over 30 that this might be a traumatic event as
  716.      the computer  will calculate  their  exact  age,  but  they  sail
  717.      blithely ahead, not believing that it will happen.  All in all, a
  718.      lot of fun and some insight into human nature.
  719.      
  720.           The second program, FOR-LISA.ZIP uses random number formulas
  721.      to generate  screen colors,  changes the  screen to 40 characters
  722.      wide, and  displays more  ASCII  graphics.    This  one  plays  a
  723.      Beethoven sonata  and takes  advantage of  some great  1982 music
  724.      programming in  BASICA that I found on a BBS.  Again, I generated
  725.      simple mathematical  formulas to  do the  work of  many lines  of
  726.      code.    Another  secret  of  programming  which  could  only  be
  727.      uncovered by doing.  Zen is doing and not doing.
  728.      
  729.           So, nothing  sensational, but now my batch files are getting
  730.      a once  over with  this new  knowledge.   Now I  realize that the
  731.      macros in  Microsoft Word, WordPerfect, and the script in ProComm
  732.      Plus are  written in BASIC.  Now these macro formulas make sense!
  733.      There has  been a  mystic clarification of macros, again like Zen
  734.      what you learn affects other areas of knowledge.
  735.      
  736.           I am  thinking of ordering from Crescent Software[3] a QUICK
  737.      BASIC  package   that  allows   you  to  program  mice,  windows,
  738.      accounting, and  databases.   Now I  have hope,  and that also is
  739.      Zen.   Yeah, nothing  sensational unless  you thought that BASICA
  740.      was another name for Zen and that "Real Men only program in C."
  741.      
  742.      References:
  743.        (1)     Somerson, Paul, PC Magazine Power Tools 2nd Edition,
  744.                Bantam Books, 1990 June;1157.
  745.        (2)     Microsoft, Programming in QuickBASIC Version 4.5,
  746.                1988;270-1.
  747.        (3)     Crescent Software, Inc; 32 Seventy Acres, West Redding,
  748.                Connecticut 06896; VOICE: 203-846-2500.
  749.      
  750.      **********************************************************************
  751.      John Richard De Palma is a California physician who practices adult
  752.      internal-medicine. Though he is old enough to know better, he has
  753.      decided to study computers. All the conversations and facts in this
  754.      article are true. Only the names and locations have been changed to
  755.      protect the unknowing and innocent who talked to him. He can be
  756.      reached on Compuserve at 76076,571 or in care of this newsletter.
  757.      **********************************************************************
  758.      
  759.      The QBNews                                                     Page 11
  760.  
  761.  
  762.      ----------------------------------------------------------------------
  763.                                 S w a p   S h o p
  764.      ----------------------------------------------------------------------
  765.  
  766.      'BARS.BAS by David Rice
  767.      '         I've  been  working  on a labor scheduling program for
  768.      '    the  past  two  years,  in  a  manufacturing  facility that
  769.      '    builds  an  automated blood analyzer for hospitals. When an
  770.      '    order  is  placed by a hospital for one of these units, the
  771.      '    Planner  must  figure out if her or his manufacturing floor
  772.      '    can  handle  the  added  hours  in labor (Standard Hours or
  773.      '    Demonstrated  (actual)  Hours), and if the added labor will
  774.      '    be  greater  than  what  the  floor  can  handle  (Capacity
  775.      '    Hours).
  776.      '
  777.      '         The  best  and easiest way for the Planner to see this
  778.      '    is  by  using  a graph. In my scheduling program there is a
  779.      '    spreadsheet  to  enter  quantities  (for  each week, month,
  780.      '    year,  or  quarter),  for each assembly. A graph allows the
  781.      '    Planner  to  see  immediately  where  she  or he has excess
  782.      '    Capacity,  so that assemblies may be scheduled during these
  783.      '    slack  periods.  Ideally,  Scheduled Actual Hours will meet
  784.      '    Capacity,  never  go  higher  than  Capacity, seldom below.
  785.      '    With a graph, this is easy to see.
  786.      '
  787.      '         In  the  sample  code here, I've excluded the Capacity
  788.      '    bar  and just included the single data set, for simplicity.
  789.      '    To  be functional, the routine must be able to handle large
  790.      '    numbers  mixed with small ones, sizing bars in proportional
  791.      '    to  their  original values. It must allow the programmer to
  792.      '    select  how  much room to leave at the top of the chart for
  793.      '    a  title,  and  how  much  room  to allow at the bottom for
  794.      '    stuff like labels, comments, etc.
  795.      '
  796.      '         I've  used  text  mode  and  not  graphics for several
  797.      '    reasons.  First  is  that  almost any computer monitor will
  798.      '    handle  the  graph.  Also,  if  one  wants to print out the
  799.      '    graph,  one  just  hits  the print-screen button. Since the
  800.      '    scheduling   program  was  designed  for  a  Novel  Netware
  801.      '    environment,  various  and vastly differing hardware may be
  802.      '    used,  and  text  mode  allows the programmer to ignore the
  803.      '    problem of different monitor types.
  804.      '
  805.      '         So  the  sample  code  is presented here for your use.
  806.      '    The  method is extremely simple, works every time, and well
  807.      '    tested.  Since  there's  no point in everyone inventing the
  808.      '    wheel,  this code is being published in the QuickBASIC News
  809.      '    letter.
  810.      '
  811.      '-------------------------- Cut Here ------------------------------
  812.      '
  813.      '     BARS.BAS
  814.      '     David Rice
  815.      '     June 16, 1990
  816.      
  817.      The QBNews                                                     Page 12
  818.      Volume  2, Number  2                                      May 31, 1991
  819.  
  820.      '
  821.      '                    Define Everything As Integer For Speed
  822.      '
  823.      defint a-z
  824.      '
  825.      '                    Top.Row.Allowed is how high you want the
  826.      '                 bars to be on the screen. Bottom.Row.Allowed
  827.      '                 is how low you want the bars to be on the
  828.      '                 screen. This is to allow text to be placed
  829.      '                 on the screen where you wish, top or bottom.
  830.      '
  831.      How.Many.Observations = 12
  832.      Top.Row.Allowed = 1
  833.      Bottom.Row.Allowed = 25
  834.      '
  835.      '                    Value!() Will Hold The 12 Bar Values. 12
  836.      '                 Was Chosen For This Example Because It Spans
  837.      '                 One Year (I.e. Bars Represent Months). TOP%()
  838.      '                 will hold the top row on the screen to draw
  839.      '                 the bars.
  840.      '
  841.      Redim Value!(How.Many.Observations),Top%(How.Many.Observations)
  842.      '
  843.      '                    Read in from the DATA statement the sample
  844.      '                 values (called "Observations").
  845.      '
  846.      for a = 1 to How.Many.Observations
  847.         read value!(a)
  848.      next
  849.      '
  850.      data 132.3,532,53,123,433,86,445,335,122,134,505,234.74
  851.      '
  852.      '                    Some other sample values you may wish
  853.      '                 to draw. No matter what range the numbers
  854.      '                 are, the largest number will define how
  855.      '                 the bars will be drawn.
  856.      '
  857.      '  data 10,20,30,40,50,60,70,80,90,100,110,120
  858.      '  data 110,100,80,60,40,20,20,40,60,80,100,110
  859.      '  data 999,1032,4343,4365,2033,2354,2335,2123,2102,325,3255,1212
  860.      '
  861.      '                    If you are using a direct screen writing
  862.      '                 utility such as QPRINT or FASTPRT, you'll
  863.      '                 want to convert the number into a string.
  864.      '                 Also, with the horizontal lines going across
  865.      '                 the screen, you'll not want leading or
  866.      '                 trailing spaces.
  867.      '
  868.      DEF FN INT.Value$(Value!)
  869.         defint a-z
  870.         '
  871.         '                 Round up value!
  872.         '
  873.         If Value! <= 32767 then Value! = cint(Value!)
  874.      
  875.      The QBNews                                                     Page 13
  876.      Volume  2, Number  2                                      May 31, 1991
  877.  
  878.         '
  879.         '                 Find how long the string will be.
  880.         '
  881.         Span% = (len(Str$(Value!)) - 1)
  882.         '
  883.         '                 Convert number to string, and remove
  884.         '              the leading space.
  885.         '
  886.         XX$ = mid$(str$(Value!),1 - (Value! >=0))
  887.         FN INT.Value$ = xx$
  888.      END DEF
  889.      '
  890.      '                    To avoid dividing by zero later,
  891.      '                 assign the variable HIGH# a negligable
  892.      '                 value. This means that if you try to
  893.      '                 graph all observations of zero, no
  894.      '                 error will occur.
  895.      '
  896.      high# = 0.02
  897.      '
  898.      '        Find The Highest Bar, and put it's value in HIGH#
  899.      '
  900.      for Bar = 1 to How.Many.Observations
  901.         if Value!(Bar) > high# then high# = Value!(bar)
  902.      next
  903.      '
  904.      '                    Define the highest bar in terms of
  905.      '                 screen rows. This could be a very small
  906.      '                 number when the values being graphed
  907.      '                 are large. The largest bar will span
  908.      '                 the screen from Top.Row.Allowed to
  909.      '                 Bottom.Row.Allowed, minus 1 for the
  910.      '                 value labels, and all other bars will
  911.      '                 be scaled using PERCENT# to this largest bar.
  912.      '
  913.      Percent# = ((Bottom.Row.Allowed - 1) / high#)
  914.      '
  915.      '                    Place horizontal lines on the screen.
  916.      '                 You may not want these, however. The
  917.      '                 next FOUR lines of code may be removed
  918.      '                 without causing problems elsewhere.
  919.      '
  920.      color 13,0,0
  921.      for row = Bottom.Row.Allowed to Top.Row.Allowed step -2
  922.         Locate row,2,0,0,0
  923.         print string$(78,196);
  924.      next
  925.      '
  926.      '                    Draw the observations. Start The Loop.
  927.      '
  928.      for Bar = 1 to How.Many.Observations
  929.         '
  930.         color 10,0,0
  931.         '
  932.      
  933.      The QBNews                                                     Page 14
  934.      Volume  2, Number  2                                      May 31, 1991
  935.  
  936.         '                 Define each value as a subset of the
  937.         '              largest.
  938.         '
  939.         XX% = (Value!(Bar) * percent#)
  940.         '
  941.         '                 Convert to screen row value.
  942.         '
  943.         Top%(Bar) = Bottom.Row.Allowed  - (xx - Top.Row.Allowed)
  944.         '
  945.         '                 Calculate the column on the screen.
  946.         '
  947.         col = (6 + (Bar - 1) * 6)
  948.         '
  949.         '                 Start at the highest row of the bar and
  950.         '              fill down to the lowest row allowed.
  951.         '
  952.         for row = top%(Bar) to Bottom.Row.Allowed
  953.            '
  954.            '              If the value is so small compared to the
  955.            '           largest, it may be too small to draw on the
  956.            '           screen. This much be checked for.
  957.            '
  958.            if row > 1 then
  959.               Locate row,col,0,0,0
  960.               '
  961.               '           Print the bar. The characters may be changed
  962.               '        of course to fit your particular needs. I've
  963.               '        included some "commented-out" samples of
  964.               '        different characters: to try them, put a
  965.               '        squote in front of the first line, and remove
  966.               '        the squote from the line you'd like to try.
  967.               '
  968.               print string$(4,219);
  969.               'print string$(4,178);
  970.               'print string$(4,176);
  971.               '
  972.            end if
  973.         next
  974.         '
  975.         '                 If you do not want the values printed at
  976.         '              the top of the bar, remove the next FIVE
  977.         '              executable lines that follow.
  978.         '
  979.         '                 Find the row to place the number.
  980.         '
  981.         Row = (Top%(Bar) - 1)
  982.         '
  983.         '                 If the bar is so small that the number
  984.         '              would be placed lower than the bottom row
  985.         '              allowed, place it on the bottom row allowed.
  986.         '
  987.         if Row > Bottom.Row.Allowed then row = Bottom.Row.Allowed
  988.         '
  989.         color 12,0,0
  990.      
  991.      The QBNews                                                     Page 15
  992.      Volume  2, Number  2                                      May 31, 1991
  993.  
  994.         Locate Row,Col,0,0,0
  995.         print FN INT.Value$(Value!(Bar));
  996.      next
  997.      '
  998.      '                    Pause for any key press. We're done!
  999.      '
  1000.      while inkey$ = ""
  1001.      wend
  1002.      ----------------------------------------------------------------------
  1003.  
  1004.      'PIES.BAS by David Rice
  1005.      '                       Make all numeric variables INTEGERS
  1006.      '
  1007.      defint a-z
  1008.      '
  1009.      '                       Random tile pattern function.
  1010.      '
  1011.      DEF FN Tile$
  1012.         DefInt a-z
  1013.         ti$ = ""
  1014.         char = 0
  1015.         Randomize timer
  1016.         '
  1017.         while char < 1
  1018.            Randomize timer
  1019.            char = ((8 * rnd) + 1)
  1020.         wend
  1021.         '
  1022.         for a = 1 to char
  1023.            Randomize timer
  1024.            b = int((255 - 32 + 1) * RND + 32)
  1025.            ti$ = ti$ + chr$(b)
  1026.         next
  1027.         fn tile$ = ti$
  1028.      END DEF
  1029.      '
  1030.      '                       For reasons of demonstration, the number
  1031.      '                    of observations (slices) in the pie chart
  1032.      '                    have been randomized to a number from 2 to
  1033.      '                    12. The maximum number of slices has been
  1034.      '                    set to 12, but if you can do without the
  1035.      '                    legends that are placed on the left of the
  1036.      '                    screen, you could make room for more slices.
  1037.      '
  1038.      start.here:
  1039.      Observations% = (rnd * 12) + 1
  1040.      if Observations% > 12 then Observations% = 12
  1041.      if Observations% = 1 then Observations% = 2
  1042.      '
  1043.      '                       Set aside room for the arrays we need.
  1044.      '
  1045.      Redim Wedge!(Observations%),Degrees!(Observations%)
  1046.      Redim Angle!(Observations%),tile$(Observations%)
  1047.      Redim x%(Observations%),y%(Observations%)
  1048.      Redim Diff!(Observations%)
  1049.      '
  1050.      
  1051.      The QBNews                                                     Page 16
  1052.      Volume  2, Number  2                                      May 31, 1991
  1053.  
  1054.      '                       Go to EGA mode, clear the screen, and
  1055.      '                    set the background color to blue (attribute
  1056.      '                    of 1). Attribute 15 looks good, too.
  1057.      '
  1058.      screen 8
  1059.      cls
  1060.      paint (3,3),1
  1061.      '
  1062.      '                       Get random tile patterns for all observations.
  1063.      '
  1064.      for tile% = 1 to Observations%
  1065.         tile$(tile%) = fn tile$
  1066.      next
  1067.      '
  1068.      '                       Find the total value for all observations.
  1069.      '                    For this demonstration, these values have been
  1070.      '                    randomized.
  1071.      '
  1072.      Total! = 0
  1073.      for a = 1 to Observations%
  1074.         '
  1075.         Wedge!(a) = (777 * RND)
  1076.         '
  1077.         If Wedge!(a) < 1 then Wedge!(a) = 1
  1078.         Total! = Total! + Wedge!(a)
  1079.      next
  1080.      '
  1081.      '                       Scale everything down to a percent of a
  1082.      '                    circle (360 degrees). Also draw the circle.
  1083.      '
  1084.      Pie.Attr% = 14
  1085.      Perc! = (total! / 360)
  1086.      circle (400,100),205,Pie.Attr%
  1087.      '
  1088.      '                       Calculate the direction to turn the line,
  1089.      '                    from a starting direction of zero (straight
  1090.      '                    up).
  1091.      '
  1092.      Direction! = 0
  1093.      '
  1094.      '                       For every observation calculate how many
  1095.      '                    degrees of the circle the slice will cover,
  1096.      '                    then the direction to turn.
  1097.      '
  1098.      for a = 1 to Observations%
  1099.         Degrees!(a) = (Wedge!(a) / Perc!)
  1100.         Direction! = Direction! + Degrees!(a)
  1101.         '
  1102.         '                    Move to the center of the pie, without
  1103.         '                 drawing a line.
  1104.         '
  1105.         Draw "BM400,100"
  1106.         '
  1107.         '                    Turn the angle and then store this angle
  1108.      
  1109.      The QBNews                                                     Page 17
  1110.      Volume  2, Number  2                                      May 31, 1991
  1111.  
  1112.         '                 for use later.
  1113.         '
  1114.         Draw "TA=" + Varptr$(Direction!)
  1115.         Angle!(a) = Direction!
  1116.         '
  1117.         '                    Draw the slice.
  1118.         '
  1119.         Draw "U86"
  1120.      next
  1121.      '
  1122.      '                       In order to fill the slice with a tile,
  1123.      '                    we need to know the center of the slice.
  1124.      '                    If we tried to PAINT outside the slice,
  1125.      '                    we would get undesirable results, such as
  1126.      '                    a screen full of trash.
  1127.      '
  1128.      '                       Calculate for every observation.
  1129.      '
  1130.      for a = 1 to Observations%
  1131.         '
  1132.         '                    If this iteration is the first, we
  1133.         '                 start from zero, take the angle the slice
  1134.         '                 was drawn, and find the middle between
  1135.         '                 the two.
  1136.         '
  1137.         If A = 1 then
  1138.            half! = (Angle!(1) / 2)
  1139.            Diff!(1) = Half!
  1140.         else
  1141.            '
  1142.            '                 For all other iterations, look for the
  1143.            '              distance between this slice and the previous
  1144.            '              one.
  1145.            '
  1146.            Half! = (ABS(Angle!(a) - Angle!(a - 1)) / 2) + Angle!(a - 1)
  1147.            Diff!(a) = (ABS(Angle!(a) - Angle!(a - 1)) / 2)
  1148.         end if
  1149.         '
  1150.         '                    Throw out a circle if there's more than one.
  1151.         '
  1152.         If Half! > 359.9999! then half! = half! - 360
  1153.         '
  1154.         '                    Go to the center of the pie, but do not draw
  1155.         '                 any line.
  1156.         '
  1157.         Draw "BM400,100"
  1158.         '
  1159.         '                    Make our new course heading good.
  1160.         '
  1161.         Draw "TA=" + Varptr$(half!)
  1162.         '
  1163.         '                    Move but DO NOT DRAW up to a point
  1164.         '                 almost but not quite to the circle's
  1165.         '                 boundry.
  1166.      
  1167.      The QBNews                                                     Page 18
  1168.      Volume  2, Number  2                                      May 31, 1991
  1169.  
  1170.         '
  1171.         Draw "BU83"
  1172.         '
  1173.         '                    Store this position, then calculate
  1174.         '                 the same for all the other observations.
  1175.         '
  1176.         x(a) = Point(0)
  1177.         y(a) = Point(1)
  1178.      next
  1179.      '
  1180.      for a = 1 to Observations%
  1181.         '
  1182.         '                    If the slice is too small to paint,
  1183.         '                 do not do so. Otherwise, paint it with
  1184.         '                 the proper tile.
  1185.         '
  1186.         If Diff!(a) > .5! then paint (X(a),Y(a)),tile$(a),Pie.Attr%
  1187.         '
  1188.         '                    Calculate the legend bubble position ROW.
  1189.         '
  1190.         Y = 10 + (A - 1) * 16
  1191.         '
  1192.         '                    Draw bubble and PAINT it with the same tile.
  1193.         '
  1194.         circle (80,y),16,Pie.Attr%
  1195.         Paint (80,y),tile$(a),Pie.Attr%
  1196.         '
  1197.         '                    Calculate the percentage of the whole this
  1198.         '                 slice is.
  1199.         '
  1200.         percent# = (wedge!(a) / total!) * 100
  1201.      next
  1202.      '
  1203.      call get.1.chr(ii$)
  1204.      '
  1205.      '                       Like a tile pattern? Hit ALT/P
  1206.      '                    and it will be saved in as a file.
  1207.      '
  1208.      If II$ = chr$(0) + chr$(25) then
  1209.         Open "Tile.Asc" for output as #1
  1210.         for a = 1 to observations%
  1211.            '
  1212.            print #1, using "Tile.Pattern$(\\) = ";mid$(str$(a),1 - (a >=0));
  1213.            '
  1214.            Size% = len(Tile$(a))
  1215.            for b = 1 to (size% - 1)
  1216.               print #1, using "CHR$(###) + ";asc(mid$(tile$(a),b,1));
  1217.            next
  1218.            print #1, using "CHR$(###)";asc(mid$(tile$(a),size%,1))
  1219.         next
  1220.         close
  1221.         call get.1.chr(ii$)
  1222.      end if
  1223.      '
  1224.      
  1225.      The QBNews                                                     Page 19
  1226.      Volume  2, Number  2                                      May 31, 1991
  1227.  
  1228.      if ii$ <> chr$(27) then goto start.here:
  1229.      '
  1230.      sub get.1.chr(i$) static
  1231.         defint a-z
  1232.         i$ = ""
  1233.         while i$ = ""
  1234.            i$ = inkey$
  1235.         wend
  1236.      end sub
  1237.      ----------------------------------------------------------------------
  1238.  
  1239.      'DIR.BAS by Dave Cleary
  1240.      '
  1241.      'One of the most useful additions to BASIC 7 PDS is the DIR$ function.
  1242.      'This function allows you to read a directory of filenames. It also
  1243.      'allows you to check the existence of a file by doing the following:
  1244.      '
  1245.      '  IF LEN(DIR$("COMMAND.COM")) THEN
  1246.      '     PRINT "File Found"
  1247.      '  ELSE
  1248.      '     PRINT "File not found"
  1249.      '  END IF
  1250.      '
  1251.      'Now QuickBASIC 4.X users can have this useful function for their
  1252.      'programs.
  1253.      '
  1254.      'Calling DIR$ with a FileSpec$ returns the the name of the FIRST
  1255.      'matching file name. Subsequent calls with a null FileSpec$ return the
  1256.      'NEXT matching file name. If a null string is returned, then no more
  1257.      'matching files were found. FileSpec$ can contain both a drive and a
  1258.      'path plus DOS wildcards. Special care should be taken when using
  1259.      'this on floppy drives because there is no check to see if the drive
  1260.      'is ready.
  1261.      
  1262.      DEFINT A-Z
  1263.      
  1264.      DECLARE FUNCTION DIR$ (FileSpec$)
  1265.      
  1266.      '$INCLUDE: 'QB.BI'
  1267.      
  1268.      '-----  Some constants that DIR$ uses
  1269.      CONST DOS = &H21
  1270.      CONST SetDTA = &H1A00, FindFirst = &H4E00, FindNext = &H4F00
  1271.      
  1272.      '--------------------------------------------------------------------
  1273.      'This shows how to call DIR$ to find all matching files
  1274.      
  1275.      'CLS
  1276.      'FileSpec$ = "C:\QB\SOURCE\*.BAS"
  1277.      'Found$ = DIR$(FileSpec$)
  1278.      'DO WHILE LEN(Found$)
  1279.      '   PRINT Found$
  1280.      '   Found$ = DIR$("")
  1281.      'LOOP
  1282.      
  1283.      '--------------------------------------------------------------------
  1284.      
  1285.      The QBNews                                                     Page 20
  1286.      Volume  2, Number  2                                      May 31, 1991
  1287.  
  1288.      
  1289.      FUNCTION DIR$ (FileSpec$) STATIC
  1290.      
  1291.         DIM DTA AS STRING * 44, Regs AS RegTypeX
  1292.         Null$ = CHR$(0)
  1293.      
  1294.      '-----  Set up our own DTA so we don't destroy COMMAND$
  1295.         Regs.AX = SetDTA                    'Set DTA function
  1296.         Regs.DX = VARPTR(DTA)               'DS:DX points to our DTA
  1297.         Regs.DS = -1                        'Use current value for DS
  1298.         InterruptX DOS, Regs, Regs          'Do the interrupt
  1299.      
  1300.      '-----  Check to see if this is First or Next
  1301.         IF LEN(FileSpec$) THEN              'FileSpec$ isn't null, so
  1302.                                             'FindFirst
  1303.            FileSpecZ$ = FileSpec$ + Null$   'Make FileSpec$ into an ASCIIZ
  1304.                                             'string
  1305.            Regs.AX = FindFirst              'Perform a FindFirst
  1306.            Regs.CX = 0                      'Only look for normal files
  1307.            Regs.DX = SADD(FileSpecZ$)       'DS:DX points to ASCIIZ file
  1308.            Regs.DS = -1                     'Use current DS
  1309.         ELSE                                'We have a null FileSpec$,
  1310.            Regs.AX = FindNext               'so FindNext
  1311.         END IF
  1312.      
  1313.         InterruptX DOS, Regs, Regs          'Do the interrupt
  1314.      
  1315.      '-----  Return file name or null
  1316.         IF Regs.Flags AND 1 THEN            'No files found
  1317.            DIR$ = ""                        'Return null string
  1318.         ELSE
  1319.            Null = INSTR(31, DTA, Null$)     'Get the filename found
  1320.            DIR$ = MID$(DTA, 31, Null - 30)  'It's an ASCIIZ string starting
  1321.         END IF                              'at offset 30 of the DTA
  1322.      
  1323.      END FUNCTION
  1324.      
  1325.      
  1326.      
  1327.      
  1328.      
  1329.      
  1330.      
  1331.      
  1332.      
  1333.      
  1334.      
  1335.      
  1336.      
  1337.      
  1338.      
  1339.      
  1340.      
  1341.      
  1342.      
  1343.      
  1344.      The QBNews                                                     Page 21
  1345.      Volume  2, Number  2                                      May 31, 1991
  1346.  
  1347.  
  1348.      ----------------------------------------------------------------------
  1349.                             T h e   T o o l   S h e d
  1350.      ----------------------------------------------------------------------
  1351.  
  1352.      A Look at Crescent Software's PDQComm by Jim Harre
  1353.      
  1354.      Product Review - PDQComm 2.50
  1355.      Source: Crescent Software
  1356.              32 Seventy Acres
  1357.              West Redding, CT 06896
  1358.              (203) 438-5300
  1359.      Price:  $99.00
  1360.      
  1361.         PDQComm 2.50 is a communications add-on library written by Dave
  1362.      Cleary (your illustrious QBNews publisher) and marketed by Crescent
  1363.      Software. Strangely enough, PDQComm does work with PDQ -- as well as
  1364.      QuickBasic 4.x and BPDS 7.x. Since PDQ doesn't provide access to the
  1365.      communications ports as QB does, an add-on package is necessary for
  1366.      serial work. PDQComm provides this feature.
  1367.      
  1368.         PDQComm provides you with over 50 low and high level routines. A
  1369.      number of the procedures have been lifted from Crescent's QuickPak
  1370.      Pro and PDQ packages. The routines are small and speedy. In short,
  1371.      it is a complete serial port programmmer's toolkit. 
  1372.      
  1373.         The documentation is absolutely first rate. Those of you upgrading
  1374.      from version 2.0 are in for a very pleasant surprise. Besides the
  1375.      usual excellent routine descriptions, a brief communications
  1376.      tutorial (including a short section on the infamous baud vs. bps
  1377.      controversy), connector pinouts, UART descriptions and register
  1378.      info, and a brief summary of 'Standard' Hayes commands and S
  1379.      registers are included at the end of the manual. If your desk looks
  1380.      like mine, it's nice to have just ONE reference with just about
  1381.      everything you need.
  1382.      
  1383.         Crescent has switched from the old, thin, 'blah' beige covers to
  1384.      attractively printed heavy card stock covers. This should help keep
  1385.      your manuals from being floppier than your disks. The only drawback
  1386.      to the manual (and this is a minor nit) is that they have changed
  1387.      the binding from a plastic spine to one of those metal double spiral
  1388.      bindings that get bent up easily and bind up the pages. At least,
  1389.      you could stick a small label on the old spines - these new ones
  1390.      don't work well for labeling.  
  1391.      
  1392.         Unlike some add-on libraries, PDQComm provides .QLB and .LIB files
  1393.      for both QB and BPDS in one package. The source code is provided as
  1394.      with all Crescent Products. A number of demonstration programs are
  1395.      provided to acquaint you with using the routines, including a TSR
  1396.      comm program.
  1397.      
  1398.      Several new features are added in version 2.50 -
  1399.        <> Two comm ports can be open simultaneously.
  1400.        <> Ports with non-standard addresses or IRQs can be opened.
  1401.        <> A function to determine the UART type has been added.
  1402.      
  1403.      The QBNews                                                     Page 22
  1404.      Volume  2, Number  2                                      May 31, 1991
  1405.  
  1406.        <> You can enable/disable the FIFO buffer in 16550 UARTS.
  1407.        <> You can adjust the receive buffer size 'on the fly'.
  1408.        <> Grab status of CTS, DSR, RI, and DCD as a TYPE variable.
  1409.        <> The timeout delay is adjustable in seconds when sending data.
  1410.        <> Several routines from PDQ are now included.
  1411.      
  1412.         QuickBasic and the Basic Professional Development System
  1413.      (otherwise known as BPDS) already have communications support built
  1414.      in -- so why would anyone buy an add-on package to do something that
  1415.      Basic already does? For the same reasons you purchased QB or BPDS when
  1416.      Basica or GW-Basic was included with your DOS -- functionality and
  1417.      flexibility. One of the great failings of the routines furnished
  1418.      with QB is that you need to use ON ERROR to trap errors.  This
  1419.      results in larger, slower code -- exactly what you don't need when
  1420.      working with communications. QB also has a VERY nasty habit of
  1421.      dropping Data Terminal Ready when you exit a program. If you are
  1422.      writing a series of programs to be executed, this is usually deadly
  1423.      to your modem connection since most modems will go onhook when you
  1424.      lower DTR.
  1425.      
  1426.         Over the last couple years that I've carried the QUIK_BAS echo on
  1427.      my system, there has been a continuing discussion on the merits of
  1428.      using a prewritten library of routines versus writing your own. It's
  1429.      no secret that I often use and advocate third party libraries. For
  1430.      me, the reason is simple - time is money. When you write code for a
  1431.      living, your production rate tends to directly affect your wages at
  1432.      salary review time. A hundred bucks for a comm package is a drop in
  1433.      the bucket compared to how long it would take me to develop (and
  1434.      especially debug) a similiar set of routines in assembly language.
  1435.      In a commercial setting and especially a production environment,
  1436.      downtime due to program 'quirks' is measured in thousands of
  1437.      dollars. Things must be solid the first time out - there isn't much
  1438.      time for playing around with it until you get it right. Over the
  1439.      last year in production programs, PDQComm has proved to be extremely
  1440.      stable and bug free.
  1441.      
  1442.         Much of my work with PDQComm has been to build TSR "device drivers"
  1443.      to communicate with digital scale indicators. Every one of these
  1444.      rascals tends to work differently, while the main application
  1445.      program needs to remain the same for the user. To avoid maintaining
  1446.      a dozen similiar but different programs, the main program simply
  1447.      issues an interrupt call and receives a numeric string from the
  1448.      scale.
  1449.      
  1450.         Before the program is launched, a small (8-9K) TSR driver is loaded
  1451.      that handles the grunt work of maintaining a conversation with the
  1452.      scale and responding to requests from the main program for
  1453.      information. This TSR is compiled using PDQ and PDQComm. Each
  1454.      different device has it's own driver that handles the peculiarities
  1455.      of that scale and has a common output format. By having the driver
  1456.      take over and handle an unused interrupt, all the main program needs
  1457.      to know is that when it calls INT 61H, the scale data magically
  1458.      appears - no matter what scale is attached. Because PDQComm can
  1459.      create compact code and PDQ can create TSR's, what would have been a
  1460.      
  1461.      The QBNews                                                     Page 23
  1462.      Volume  2, Number  2                                      May 31, 1991
  1463.  
  1464.      real drudge with ASM is now almost easy - in BASIC.
  1465.      
  1466.         To give you an idea what programming with PDQComm feels like,
  1467.      here's a small program and comments (lifted directly from the PDQComm
  1468.      manual):
  1469.      
  1470.         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1471.      
  1472.         Besides using a syntax as close to BASIC's as possible, PDQComm
  1473.         also returns error information in the BASIC ERR function. This
  1474.         lets you easily test the success or failure of the most recent
  1475.         operations, without requiring ON ERROR. Unlike other communi-
  1476.         cations libraries you may have seen, PDQComm uses the minimum
  1477.         number of parameters possible. This greatly reduces the size of
  1478.         your programs, and also improves their speed.
  1479.      
  1480.         DEFINT A-Z                                 'all integers please
  1481.      
  1482.         DECLARE SUB OpenCom (Action$)              'same as OPEN "COM..."
  1483.         DECLARE SUB ComPrint (Work$)               'same as PRINT #n,
  1484.         DECLARE SUB CloseCom ()                    'same as CLOSE #n
  1485.         DECLARE FUNCTION BIOSInkey% ()             'similiar toASC(INKEY$)
  1486.         DECLARE FUNCTION ComEof% ()                'same as EOF(n)
  1487.         DECLARE FUNCTION ComInput$(NumChars)       'same as INPUT$(n,#n)
  1488.         CALL OpenCom("COM1:2400,N,8,1,RB512,XON")  'open the port
  1489.         IF ERR THEN  'oops
  1490.           PRINT "Error opening the communications port."
  1491.           END
  1492.         END IF
  1493.       
  1494.         DO
  1495.           Char = BIOSInkey%                        'get what was typed
  1496.           IF Char = 27 THEN EXIT DO                'exit if it was Escape
  1497.           IF Char THEN CALL ComPrint(CHR$(Char))   'anything else, send it
  1498.           IF NOT(ComEof%) THEN                     'was anything received?
  1499.             ComString$ = ComInput$(ComLoc%)        'yes, get the characters
  1500.             PRINT ComString$;                     'print them on the screen
  1501.           END IF
  1502.         LOOP                                       'loop forever
  1503.      
  1504.         CALL CloseCom                              'close the port and end
  1505.      
  1506.         Here, the OpenCom routine is called specifying communications
  1507.         port 1 at a baud rate of 2400, no parity, 8 data bits, and 1 stop
  1508.         bit. RB512 specifies a receive buffer size of 512 bytes, and XON
  1509.         indicates that XON/XOFF handshaking is to be performed automat-
  1510.         ically. We will discuss handshaking as well as selecting an
  1511.         appropriate buffer size in a moment.
  1512.      
  1513.         Once the communications port has been opened, an "endless" loop
  1514.         is entered that alternately checks for keyboard activity and
  1515.         characters being received. If a character has been entered at the
  1516.         keyboard it is sent through the port (unless it was the Escape
  1517.         key). And if any characters have been received and are waiting to
  1518.      
  1519.      The QBNews                                                     Page 24
  1520.      Volume  2, Number  2                                      May 31, 1991
  1521.  
  1522.         be read, the ComInput$ function reads all of them from the receive
  1523.         buffer.
  1524.      
  1525.         The ComEof% function is used to determine if any characters are
  1526.         waiting in the buffer. ComLoc% reports how many, and ComInput$
  1527.         does the actual reading. Notice that these functions are identical
  1528.         to the equivalent BASIC functions EOF(), LOC(), and INPUT$
  1529.         respectively.
  1530.      
  1531.         The BIOSInkey function is much more efficient than the regular
  1532.         QuickBASIC INKEY$, because it returns the integer ASCII value
  1533.         of the key that was pressed. This requires less code in the BASIC
  1534.         program, since integer assignments and comparisons are simpler
  1535.         than the equivalent string operations.
  1536.      
  1537.         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  1538.      
  1539.         As you can see, using PDQComm isn't too much different from
  1540.      standard QB or BPDS. Of course, this simple terminal program doesn't
  1541.      show off all the features of the library. You can set the amount of
  1542.      time to wait to transmit using ComPrint$. If you'd rather use RTS/CTS
  1543.      hardware handshaking instead of software XON/XOFF, it's available.
  1544.      If you want to run another program after closing the comm port but
  1545.      not drop the line, a routine called SetMCRExit allows you to select
  1546.      what happens to the state of the DTR and RTS lines when the port
  1547.      closes. PDQComm has low-level routines to handle just about any task
  1548.      you can imagine with the serial ports of your PC.
  1549.      
  1550.         What about high-level stuff? Crescent packages are famous for
  1551.      throwing in a number of BASIC routines that not only illustrate the
  1552.      usage of the low-level routines, but provide you with easy to use
  1553.      building blocks for your own programs. Several terminal programs are
  1554.      provided including one that runs as a TSR. For those of you who need
  1555.      to transfer files, there are routines for transferring an ASCII file
  1556.      (somewhat useless, in my opinion) and a set of XMODEM routines for
  1557.      both checksum and CRC (far more useful).
  1558.      
  1559.         If you need to talk to a terminal, terminal emulation routines are
  1560.      provided for TTY, ANSI (PC), VT52 & VT100 (Digital Equipment), and
  1561.      D215 (Data General). Routines are provided to define multiple
  1562.      windows on the screen - each running a different emulation if you
  1563.      wish.
  1564.      
  1565.         If you are looking for source code to a basic, high performance
  1566.      term program that you can customize to your heart's content, PDQComm
  1567.      furnishes you with enough tools and toys to keep you busy for
  1568.      months. The AnsiTerm program included works rather nicely as an
  1569.      example of what you can do with the package; it shows off both ANSI
  1570.      emulation and XMODEM file transfers. It also demonstrates the use of
  1571.      the XStat routine, a pop-up status window for tracking XMODEM
  1572.      transfers.
  1573.      
  1574.         Technical Support is something that Crescent does well. While
  1575.      digging through this package, I ran into a problem running one of
  1576.      
  1577.      The QBNews                                                     Page 25
  1578.      Volume  2, Number  2                                      May 31, 1991
  1579.  
  1580.      the demo programs (DemoAnsi). A call to Crescent solved the problem
  1581.      with a minimum of fuss. If I'd really read the documentation instead
  1582.      of skimming it, I'd have found the problem. Instead of reminding me
  1583.      what a dummy I was for not fully reading the manual, the person on
  1584.      the other end of the phone (Nash) kindly led me through uncommenting
  1585.      some lines of code to make things work. Microsoft could learn a few
  1586.      things about customer service from these people. (I wish they
  1587.      would!)
  1588.      
  1589.         Nothing in this world (especially in programming) is perfect, but
  1590.      PDQComm has few flaws. For those planning to write their own BBS, it
  1591.      would be nice to see more file transfer routines though it can be
  1592.      easily argued that external programs (like DSZ) can be used to
  1593.      provide that service.  Other than that, and my earlier nit-picking
  1594.      about the binding, there's not much to complain about.
  1595.      
  1596.         To sum up, PDQComm is an excellent communications package for BASIC
  1597.      programmers. It has a well written manual, plenty of examples that
  1598.      will interest the novice, and plenty of routines to satisfy the more
  1599.      advanced programmer. Tech support is very good and the routines work
  1600.      as advertised. The package continues to be improved and Crescent has
  1601.      already announced that they will be selling a version of PDQComm for
  1602.      the new Visual Basic. Overall, if you are looking for a competent
  1603.      communications package, this is money well spent.
  1604.      
  1605.      **********************************************************************
  1606.      Jim Harre is an avid QuickBASIC programmer from St. Louis. He also
  1607.      runs a BBS that has been in operation since it ran on a TSR-80. You
  1608.      can call his BBS at 314-843-0001 or write to him in care of this
  1609.      newsletter.
  1610.      **********************************************************************
  1611.      
  1612.  
  1613.  
  1614.  
  1615.  
  1616.  
  1617.  
  1618.  
  1619.  
  1620.  
  1621.  
  1622.  
  1623.  
  1624.  
  1625.  
  1626.  
  1627.  
  1628.  
  1629.  
  1630.  
  1631.  
  1632.  
  1633.  
  1634.      The QBNews                                                     Page 26
  1635.      Volume  2, Number  2                                      May 31, 1991
  1636.  
  1637.  
  1638.  
  1639.      ----------------------------------------------------------------------
  1640.         W h o   y a   g o n n a   c a l l ?   C A L L   I N T E R R U P T
  1641.      ----------------------------------------------------------------------
  1642.  
  1643.      Working with the Rodent by Daniel R. Berry
  1644.      
  1645.         The Rodent (mouse) is one of the easiest input devices for computer 
  1646.      users to adapt to.  It allows great flexibility for entering data, 
  1647.      moving around screens and using menus.  Over the last few years the 
  1648.      Rodent has truly found a home with computer users.   This leads you to
  1649.      wonder why new programs enter the market without mouse interfaces.
  1650.      Probably the most common reason for this oversight is the Rodent
  1651.      intimidates programmers.  The pesky little critter isn't the easiest
  1652.      user interface to program for.  Yet,  adding a mouse interface to your
  1653.      programs is easier than most think.
  1654.      
  1655.         The mouse functions operate through a device driver such as
  1656.      MOUSE.SYS or MOUSE.COM provided with most MS-DOS compatible rodent
  1657.      species.  This driver ties itself to interrupt 33H allowing the
  1658.      programmer direct accessed to the mouse functions.  Several programmer
  1659.      references document this interrupt and its functions detailing the
  1660.      features and complexities of the mouse driver.  Over the last few
  1661.      years I have played around with mouse interfaces and have finally
  1662.      developed a set of routines that allow me to add a mouse interface to
  1663.      any QuickBASIC program I write.  The routines provide access to most
  1664.      of the mouse functions and they aren't that hard to use.
  1665.      
  1666.      To use these routines in your program you must use the following 
  1667.      statement at the beginning of your program:
  1668.      
  1669.           COMMON SHARED /Mouse/ MouseChk%, MouseStat%
  1670.           (This statement is provided in the MOUSE.BI file.)
  1671.      
  1672.      The routines use these variables to track the following:
  1673.      
  1674.           MouseChk% indicates the availability of an active mouse driver 
  1675.      and the status of these routines (1=Enabled / 0=Disabled).  
  1676.      
  1677.           MouseStat% shows the status of the mouse cursor or pointer 
  1678.      (1=On / 0=Off).
  1679.      
  1680.         Mouse is the heart of the mouse utilities.  It provides access to 
  1681.      interrupt 33h using INTERRUPT provided in the QB.QLB.  Almost all the
  1682.      other mouse routines call Mouse to complete their functions.
  1683.      
  1684.           Usage:  CALL Mouse (M1%, M2%, M3%, M4%)
  1685.      
  1686.           M1 - M4 are the system registers AX - DX respectively.
  1687.      
  1688.         MouseCheck is the second most important of these routines.  
  1689.      MouseCheck can determine mouse driver availability; enable the mouse
  1690.      driver; or disable the mouse driver.  This routine must be called at
  1691.      the beginning of your program if you want to use the mouse.
  1692.      
  1693.      
  1694.      The QBNews                                                     Page 27
  1695.      Volume  2, Number  2                                      May 31, 1991
  1696.  
  1697.         MouseChk updates MouseChk% and MouseStat% as applicable.  You
  1698.      should note that when the mouse driver is installed the mouse cursor
  1699.      is set to off.
  1700.      
  1701.           Usage:  CALL MouseCheck (MFlag%)
  1702.      
  1703.           MFlag% = If set to -1 the mouse will be installed, if 
  1704.      available (if not already done so).  If set to -2 the mouse 
  1705.      routines will be disabled.  Any other value will cause this routine 
  1706.      to determine if the mouse has been installed.  A returned value of 
  1707.      1 indicates that the mouse driver is installed, 0 indicates that 
  1708.      the mouse driver has not been installed or is disabled.  
  1709.      
  1710.         MouseCRT will determine or set the mouse video display page.  This 
  1711.      is useful when your programs use multiple display pages.
  1712.      
  1713.           Usage:  CALL MouseCRT(CRT%, Flag%)
  1714.      
  1715.           The video display page is determined or set by using the CRT% 
  1716.      variable.  Flag% is used to toggle 0=set/1=determine.
  1717.      
  1718.         MouseInformation provides specific information for the Rodent used 
  1719.      by the system.  This routine provides the mouse driver software 
  1720.      version and mouse type.  
  1721.      
  1722.           Usage:  Call MouseInformation(MouseVer$, MouseType%,
  1723.                   MouseType$)
  1724.      
  1725.           MouseVer$ is the current mouse driver version.
  1726.      
  1727.           MouseType% and MouseType$ represent the following:
  1728.      
  1729.           1 - Bus Mouse       2 - Serial Mouse    3 - InPort Mouse
  1730.           4 - PS/2 Mouse      5 - HP Mouse
  1731.      
  1732.         MouseLeft determines the position of the mouse at the last left 
  1733.      button depression.  Also determines the number of depressions of the
  1734.      left button since this routine was last called.  Position is returned
  1735.      in screen pixels.
  1736.      
  1737.           Usage:  CALL MouseLeft (LCount%, MouseX%, MouseY%)
  1738.      
  1739.           LCount% = The number of left button depressions since the 
  1740.      routine was last called.
  1741.      
  1742.         MouseLeftRC functions the same as MouseLeft except position is 
  1743.      determined by screen row and column.
  1744.      
  1745.           Usage:  CALL MouseLeftRC (LCount%, MRow%, MCol%)
  1746.      
  1747.         MouseLightPen will enable (1) or disable (0) mouse light pen 
  1748.      emulation mode.  Calls to the Basic PEN function return the last pen
  1749.      down location.  Pen down is set when both buttons are depressed.
  1750.      
  1751.      
  1752.      The QBNews                                                     Page 28
  1753.      Volume  2, Number  2                                      May 31, 1991
  1754.  
  1755.           Usage:  CALL MouseLightPen (Status%)
  1756.      
  1757.         MouseLimits will set the mouse limits restricting movement to a 
  1758.      specific area.  Limits are set using screen pixels.
  1759.      
  1760.           Usage:  CALL MouseLimits(MouseX1%, MouseY1%, MouseX2%, 
  1761.      MouseY2%)
  1762.      
  1763.           MouseX1/Y1% = Upper left corner horizontal/vertical (X/Y) 
  1764.      position.
  1765.      
  1766.           MouseX2/Y2% = Lower right corner horizontal/vertical (X/Y) 
  1767.      position.
  1768.      
  1769.         MouseLimitsRC functions the same as MouseLimits except the limits 
  1770.      are determined by screen row and column.
  1771.      
  1772.           Usage:  CALL MouseLimitsRC(MRow1%, MCol1%, MRow2%, MCol2%)
  1773.      
  1774.           MRow1%/MCol1% = Upper left corner row/column limit.
  1775.      
  1776.           MRow2%/MCol2% = Lower right corner row/column limit.
  1777.      
  1778.         MouseLocate locates the mouse cursor at a specified X and Y 
  1779.      coordinate.  Coordinates are set in screen pixels.
  1780.      
  1781.           Usage:  CALL MouseLocate(MouseX%, MouseY%)
  1782.      
  1783.         MouseLocateRC functions the same as MouseLocate except coordinates 
  1784.      are set at specified row and column. 
  1785.      
  1786.           Usage:  CALL MouseLocateRC(MRow%, MCol%)
  1787.      
  1788.         MouseMotion returns the horizontal and vertical mouse motion 
  1789.      counters.  Motion counts are in 1/200 inch increments. 
  1790.      
  1791.           Usage:  CALL MouseMotion(Horz%, Vert%)
  1792.      
  1793.           Horz% = Horizontal motion counter value (positive = right 
  1794.      motion / negative = left motion).
  1795.      
  1796.           Vert% = Vertical motion counter value (positive = downward 
  1797.      motion / negative = upward motion).
  1798.      
  1799.         MouseOn / MouseOFF turns the mouse cursor on/off as desired.  These 
  1800.      functions use MouseStat% to determine the status of the cursor and 
  1801.      take action only when needed.  This check is used to prevent the 
  1802.      internal cursor flag from being modified unnecessarily.
  1803.      
  1804.           Usage:  CALL MouseOn / MouseOff
  1805.      
  1806.         MouseRelease returns the position of the mouse after the button 
  1807.      requested was last released.  Position is returned in screen pixels.
  1808.      
  1809.      
  1810.      The QBNews                                                     Page 29
  1811.      Volume  2, Number  2                                      May 31, 1991
  1812.  
  1813.           Usage:  CALL MouseRelease(Button%, Count%, MouseX%, MouseY%)
  1814.      
  1815.           Button% = The button to be checked (0 = left / 1=right).
  1816.      
  1817.           Count% = The number of button releases since the last call to 
  1818.      this routine.
  1819.      
  1820.         MouseReset resets the mouse driver to the default values and
  1821.      updates MouseStat%.
  1822.      
  1823.           Mouse Position:  Screen Center     Mouse Cursor:  Off
  1824.           Light Pen Emulation:  On           CRT Page Number:  0
  1825.      
  1826.           Usage:  CALL MouseReset
  1827.      
  1828.         MouseRight determines the position of the mouse at the last right 
  1829.      button depression.  Also determines the number of depression of the 
  1830.      right button since this routine was last called.  Position is returned
  1831.      in screen pixels.
  1832.      
  1833.           Usage:  CALL MouseRight(RCount%, MouseX%, MouseY%)
  1834.      
  1835.         MouseRightRC functions the same as MouseRight except position is 
  1836.      determined by screen row and column.
  1837.      
  1838.           Usage:  CALL MouseRightRC (RCount%, Row%, Col%)
  1839.      
  1840.         MouseSensitivity enables programmers to determine or modify mouse 
  1841.      sensitivity to better suit their needs.  Horizontal and vertical 
  1842.      movement are defined in mickeys.  One mickey equals 1/200-inch of 
  1843.      mouse travel.  Mickeys range from 1 to 32,767 (horizontal default is 8
  1844.      and vertical default is 16).  Doublespeed sets threshold for doubling
  1845.      mouse cursor movement (default 64 mickeys/second).
  1846.      
  1847.           Usage:  CALL MouseSensitivity(GetSet%, HMickey%, VMickey%,
  1848.                   DoubleSpeed%)
  1849.      
  1850.           GetSet% is used to toggle 0 = Get / 1 = Set.
  1851.      
  1852.         MouseStatus determines Mouse Status to include position and buttons 
  1853.      currently depressed.  Position is returned in screen pixels.
  1854.      
  1855.           Usage:  CALL MouseStatus(Left%, Right%, MouseX%, MouseY%)
  1856.      
  1857.           Left% = If returned as 1 then the left button is depressed.
  1858.      
  1859.           Right% = If returned as 1 then the right button is depressed.
  1860.      
  1861.         MouseStatusRC functions the same as MouseStatus except position is 
  1862.      returned by screen row and column.
  1863.      
  1864.           Usage:  CALL MouseStatusRC(Left%, Right%, MRow%, MCol%)
  1865.      
  1866.         RODENT.BAS provides a demonstration of these routines and designed 
  1867.      
  1868.      The QBNews                                                     Page 30
  1869.      Volume  2, Number  2                                      May 31, 1991
  1870.  
  1871.      to give you a general idea of how the mouse interface works.  If your
  1872.      rodent is having a problem working with these routines read your users
  1873.      manual to ensure that you have MS Mouse emulation active.
  1874.      
  1875.         Well, that's about it.  I have included a few support routines from 
  1876.      my library to give RODENT.BAS some flair and the *.BIT routines are 
  1877.      needed by MOUSE.MOU to work with some of the bits returned in the 
  1878.      system registers.  You have everything you need to get that pesky 
  1879.      rodent to work so why not put that $50 - $90 toy to some use and 
  1880.      program!  
  1881.      
  1882.         Please feel free to write.  I am open to comments, suggestions and 
  1883.      will even answer a question or two.  Complaints are received only on
  1884.      Friday, must be in triplicate (no carbons please), must be signed by
  1885.      your mother, and be accompanied by a personal check for $200.00.
  1886.      (Laugh - my wife did!)
  1887.      
  1888.      [EDITOR'S NOTE]
  1889.      All source code for this article is contained in RODENT.ZIP.
  1890.      
  1891.      **********************************************************************
  1892.           Daniel Berry is a member of the U.S. Air Force.  Off-duty he 
  1893.      writes a utility library for QuickBASIC.  Daniel may can be reached 
  1894.      at 3110-C South General McMullen, San Antonio, TX 78226.
  1895.      **********************************************************************
  1896.      
  1897.  
  1898.  
  1899.  
  1900.  
  1901.  
  1902.  
  1903.  
  1904.  
  1905.  
  1906.  
  1907.  
  1908.  
  1909.  
  1910.  
  1911.  
  1912.  
  1913.  
  1914.  
  1915.  
  1916.  
  1917.  
  1918.  
  1919.  
  1920.  
  1921.  
  1922.  
  1923.  
  1924.  
  1925.      The QBNews                                                     Page 31
  1926.      Volume  2, Number  2                                      May 31, 1991
  1927.  
  1928.      A Graphics Mouse Cursor Design System by Dr. Warren G. Lieuallen
  1929.      
  1930.           MOUSCURS.BAS will allow you to draw your own graphics cursor
  1931.      design without having to worry about all those crazy hex numbers,
  1932.      and what to do with them!  You'll simply draw your cursor shape
  1933.      on the screen, and then save the data.  A complete, stand-alone
  1934.      QuickBASIC program will be created which will simply define your
  1935.      cursor and turn it on.  The purpose of this is for you to then
  1936.      add the rest of your program; MOUSCURS will have taken care of
  1937.      the nitty-gritty of your custom mouse cursor.  For the more
  1938.      adventurous of you, you can also save only the DATA statements,
  1939.      and then do with them what you will.
  1940.      
  1941.           MOUSCURS.BAS was designed and tested on a Hercules
  1942.      monochrome system, and checked on a VGA system.  It should work
  1943.      with any graphics system, but I've not used it with CGA or EGA. 
  1944.      If you have trouble, feel free to fiddle with the code yourself.
  1945.      
  1946.           To use MOUSCURS.BAS, you must load QuickBASIC with CALL
  1947.      Interrupt support.  The easiest way to do this is to load the
  1948.      QB.QLB quick library by entering "QB /L QB" to run QuickBASIC. 
  1949.      You'll also need CALL Interrupt support for your program which
  1950.      uses MOUSCURS to define the cursor.  My recommendation is to add
  1951.      the CALL Interrupt routine to your own custom quick library;
  1952.      that's what I did!
  1953.      
  1954.           Once you run MOUSCURS, you'll seen the main (and only!)
  1955.      screen.  You can now use your mouse to draw a shape.  Move around
  1956.      the "cursor mask" screen; pressing the LEFT button will toggle
  1957.      the individual pixels on and off.  Once your shape is defined
  1958.      (you'll see a true-size representation of the cursor in the
  1959.      "Custom Cursor" window), you'll then need to work on the screen
  1960.      mask.  The easiest way to do this is to click on the "Expand". 
  1961.      This will copy your cursor to the screen mask window, and draw a
  1962.      border around it automatically.  You can then edit it to
  1963.      perfection; watch the "Custom Cursor" window to see what the
  1964.      cursor looks like on a "normal" and "inverse" screen.
  1965.      
  1966.           Before you finish, you must also define a "hot spot".  This
  1967.      is the single pixel which defines the cursor's location (e.g. the
  1968.      spot that must be inside the button you're clicking on).  To
  1969.      select a "hot spot" click the RIGHT button in the cursor mask
  1970.      window.  The hot spot will be indicated by an "X".  However, by
  1971.      clicking in the same spot, you can define an "invisible" hot
  1972.      spot, which will be defined by a "0".  The best way to learn how
  1973.      the RIGHT button works is to just play with it, and watch the
  1974.      "Custom Cursor" window to see if the spot is turned on or off. 
  1975.      Also, remember to use the RIGHT button for the hot spot, and the
  1976.      LEFT button for everything else.
  1977.      
  1978.           At any time, you can also clear either of the windows by
  1979.      clicking on the "Clear" buttons.  You can also copy the cursor
  1980.      mask to the screen mask by clicking on the "Copy" button.
  1981.      
  1982.      
  1983.      The QBNews                                                     Page 32
  1984.      Volume  2, Number  2                                      May 31, 1991
  1985.  
  1986.           Finally, as a test of your new cursor, you can click on the
  1987.      "Activate" button to replace the cursor with your own design.  Be
  1988.      sure you have something defined before you do this, or you'll
  1989.      lose the cursor, and won't be able to see what you're doing!  You
  1990.      can turn your cursor back off and return to the hand by clicking
  1991.      on the "DeActivate" button.
  1992.      
  1993.           Once your cursor is finished, you can save it by clicking on
  1994.      either the "Save Data" or "Save Program" buttons.  "Save Data"
  1995.      does just what it says; it will save only the DATA statements
  1996.      needed to define your custom cursor.  "Save Program" will create
  1997.      a stand-alone program that will define your cursor and turn it on
  1998.      (in fact, you can run this program just to see what your cursor
  1999.      looks like once you're done).  Both of these options create a
  2000.      file called CURSORn, with "n" being a sequential number; you will
  2001.      not overwrite existing cursor files (old files must be deleted
  2002.      manually).  Data is saved with a .BI extension; programs are
  2003.      saved with the standard .BAS extension.  You can, of course,
  2004.      rename any of these files after you've created them via DOS.
  2005.      
  2006.           Finally, if you've already created some cursors, you can
  2007.      edit them by using the "Load Cursor" button.  You'll be asked to
  2008.      provide the filename and extension; the data will then be loaded
  2009.      and the cursor displayed just as you had drawn it.
  2010.      
  2011.           Feel free to examine the code of MOUSCURS.BAS.  It was
  2012.      written primarily as an learning exercise; there are undoubtedly
  2013.      other (and probably better!) ways to accomplish the same task. 
  2014.      MOUSCURS.BAS was my first (and so far, only) graphic program, so
  2015.      please bear with me.  For more details on programming mouse
  2016.      functions in QuickBASIC, refer to the QB News (volume 2,
  2017.      number 2).
  2018.      
  2019.      [EDITOR'S NOTE]
  2020.      The code for this article can be found in MOUSECUR.ZIP. This program
  2021.      will not work in the QBX environment or with far strings. This
  2022.      program also requires the DIR$ function contained in the SwapShop
  2023.      section of this newsletter.
  2024.      
  2025.  
  2026.  
  2027.  
  2028.  
  2029.  
  2030.  
  2031.  
  2032.  
  2033.  
  2034.  
  2035.  
  2036.  
  2037.  
  2038.  
  2039.  
  2040.      The QBNews                                                     Page 33
  2041.  
  2042.  
  2043.      ----------------------------------------------------------------------
  2044.           T h e   Q B N e w s   P r o f e s s i o n a l   L i b r a r y
  2045.      ----------------------------------------------------------------------
  2046.  
  2047.      Fast Screen Printing by Christy Gemmel
  2048.      
  2049.      [EDITOR'S NOTE]
  2050.      All code for this article may be found in FASTPRNT.ZIP. This article
  2051.      also refers to figures which included in FIGURES.TXT which is in
  2052.      FASTPRNT.ZIP.
  2053.      
  2054.      This article  presents a  rapid method of displaying a string of ASCII
  2055.      characters on  the screen  without updating  the cursor  position. The
  2056.      calling program should pass the string, the row/column co-ordinates of
  2057.      the screen  location where  it is  to be printed and the number of the
  2058.      colour or display attribute required.
  2059.      
  2060.      Many routines  in my Assembly-Language Toolbox are concerned with  the
  2061.      video  display, this  being  the  primary  means  through   which   we
  2062.      communicate with  the users  of our program. Later, when we get around
  2063.      to developing such things as Popup Windows and Dialogue Boxes, we will
  2064.      need to  acquire some pretty sophisticated screen-handling techniques.
  2065.      For now,  however, let  us look at the more mundane task of displaying
  2066.      text on the screen.
  2067.      
  2068.      For most  applications   the QuickBASIC  PRINT statement  is perfectly
  2069.      adequate. Because  it is  a general-purpose  statement, however, which
  2070.      can be  used to  direct output  to the printer or a file as well as to
  2071.      the screen,  PRINT is not as fast as it might be. Moreover, to display
  2072.      a string  of characters  at a  specific place  on the  screen you must
  2073.      first position  the cursor  with a LOCATE statement. Then, if you want
  2074.      to display  the string in a different colour than the background text,
  2075.      you must  issue a preliminary COLOR statement before printing. What we
  2076.      need is  a screen-specific  display routine  that combines these three
  2077.      statements into  one. Naturally,  since we are going to the trouble of
  2078.      writing it  in Assembly-Language,  we expect  it  to  be  as  fast  as
  2079.      possible.
  2080.      
  2081.      Let us, then, set out our objectives for FastPrint:
  2082.      
  2083.      1)   The ROW/COLUMN  location where  the string  is to  be printed  is
  2084.           specified to the routine, so that there is no need for a seperate
  2085.           LOCATE statement to position the cursor.
  2086.           
  2087.      2)   You must  be able  to place  the string  anywhere on the display,
  2088.           including the  bottom line  of the  screen, no  matter what  VIEW
  2089.           PRINT parameters may be in effect.
  2090.           
  2091.      3)   Output to  the bottom  line of  the display  should not cause the
  2092.           screen to scroll.
  2093.           
  2094.      4)   You should be able to specify the colour and/or display attribute
  2095.           of the  text to  be printed,  so there  is no need for a seperate
  2096.           COLOR statement.  Furthermore the attribute specified should appy
  2097.      
  2098.      The QBNews                                                     Page 34
  2099.      Volume  2, Number  2                                      May 31, 1991
  2100.  
  2101.           only to  the text being printed, it must not effect the colour of
  2102.           any subsequent PRINT statements.
  2103.           
  2104.      5)   To obtain maximum performance, FastPrint should write directly to
  2105.           video display  memory. This  will be  particularly useful when we
  2106.           need to output large blocks of text.
  2107.      
  2108.      This last  clause needs  some explanation.  In general,  there are two
  2109.      methods of outputting text to the screen. The first makes calls to the
  2110.      video services  built into the PC's ROM-BIOS and can, consequently, be
  2111.      used by  any computer  that is  BIOS-compatible with the IBM family of
  2112.      personal computers. This method, however, is considered to be a little
  2113.      slow by today's standards.
  2114.      
  2115.      The alternative  technique bypasses  ROM-BIOS  completely  and  writes
  2116.      directly to  the video display buffer. Since the display, in most PCs,
  2117.      is mapped  by the  video hardware  to a  fixed location in memory, any
  2118.      characters that  are written  to this  area will immediately appear on
  2119.      the  screen.   This  is  the  fastest  method  of  all,  but  has  the
  2120.      disadvantage that  it will  only work  on computers that are hardware-
  2121.      compatible with  the original IBM PC. However, since this includes all
  2122.      modern XT,  AT and  PS/2 class machines, it is not unduly restrictive,
  2123.      but it does eliminate some older models like the Tandy 2000.
  2124.      
  2125.      We will adopt the second method. It is, after all, the one used by 90%
  2126.      of today's software and has become something of a de facto standard in
  2127.      its' own  right. This  is the  only  way  we  can  achieve  some  real
  2128.      performance in our programs.
  2129.      
  2130.      The bulk  of the  work is  done by a short assembly-language procedure
  2131.      that is  designed to  be called  from QuickBASIC.  It can be part of a
  2132.      Quick Library for use in the programming environment or assembled into
  2133.      a single  module that  can be  linked to stand-alone programs compiled
  2134.      with BC's /O switch. I will show you both methods later.
  2135.      
  2136.      Although short,  FASTPRINT  illustrates  some  important  features  of
  2137.      mixed-language programming  that I will discuss in some detail. It was
  2138.      written for  MicroSoft's Macro  Assembler (MASM) version 5.1 and makes
  2139.      use of  the simplified  segment directives  that are a feature of that
  2140.      assembler. This  lets us  define the  Memory Model  of the  routine to
  2141.      match that of the calling program.
  2142.      
  2143.                     .model    medium
  2144.      
  2145.      All QuickBASIC  programs use the MEDIUM memory model, which means that
  2146.      all simple data fits within a single 64K segment, although the program
  2147.      code may  be greater  than 64K.  When we enter the routine, therefore,
  2148.      the DS  (Data Segment)  register is  already pointing  to the  segment
  2149.      containing the string of characters we will be printing and we can use
  2150.      near pointers,  offset from  DS, to  address  this  string.  The  main
  2151.      procedure, however, must be declared FAR so that the Code Segment (CS)
  2152.      register is set correctly when it is called. FastPrint is the name you
  2153.      will be using when you call this routine from your program, declare it
  2154.      PUBLIC so that QuickBASIC can find it.
  2155.      
  2156.      The QBNews                                                     Page 35
  2157.      Volume  2, Number  2                                      May 31, 1991
  2158.  
  2159.      
  2160.                     public    FastPrint
  2161.      
  2162.      Now for the routine itself, here are the first few lines:
  2163.      
  2164.                     .code
  2165.      
  2166.      FastPrint      proc far
  2167.                     push bp                  ; Save Base pointer
  2168.                     mov  bp,sp               ; Establish stack frame
  2169.                     push es                  ; Save Extra Segment
  2170.                     push si                  ;    and index pointers
  2171.                     push di
  2172.      
  2173.      Remember that QuickBASIC uses the Medium Memory model. This means that
  2174.      we can't  assume our  assembled routine  will be  linked into the same
  2175.      code segment  as the main program that calls it, so the procedure must
  2176.      be declared as FAR. The next two lines are concerned with setting up a
  2177.      pointer to  the stack so that we can easily get at the parameters that
  2178.      the routine  is expecting,  more about  this in a minute. We must also
  2179.      preserve the values of any segment registers (except for CS, which has
  2180.      already been  modified by  the call  itself) that  are altered  by the
  2181.      routine, also the Index registers DI and SI if they are used.
  2182.      
  2183.      When the  routine  is  called,  QuickBASIC  pushes  a  two-byte  value
  2184.      corresponding to  each of  the supplied  parameters onto  the  program
  2185.      stack. These are followed by the return address which, since this is a
  2186.      FAR procedure,  is a  four-byte pointer  (Segment and  Offset) to  the
  2187.      statement following  the call  to FastPrint.  When  we  have  finished
  2188.      saving our own working registers, the stack will look like this:
  2189.      
  2190.      Figure 1.1     Stack contents after entry into FastPrint.   
  2191.      
  2192.      Note that,  since we  copied the  contents of  the Stack Pointer to BP
  2193.      immediately after  BP itself was pushed, This register can now be used
  2194.      as a  fixed pointer  through which  we access the parameters that were
  2195.      passed. Normally,  QuickBASIC passes  these arguments as 2-byte offset
  2196.      addresses, which  point to  the named  variables in the program's Data
  2197.      Segment.
  2198.      
  2199.      We, however, are going to override this and pass the numeric arguments
  2200.      BY VALue,  forcing QuickBASIC  to copy  the  actual  contents  of  the
  2201.      variables into the appropriate stack locations. Then all we need do is
  2202.      read the data supplied, directly into the target registers:
  2203.      
  2204.                     mov  ax,[bp+12]          ; Get row number
  2205.      
  2206.      Passing by  VALUE saves us having to hunt for the variables containing
  2207.      our data  and so  makes our  routine faster and more compact. It also,
  2208.      incidently, makes  it easier if we ever need to convert FastPrint to a
  2209.      C function, since the C language does it by default. We'll make use of
  2210.      the technique  in a  minute or  two, but  first we  must collect  some
  2211.      important information about the computer our program is running in.
  2212.      
  2213.      
  2214.      The QBNews                                                     Page 36
  2215.      Volume  2, Number  2                                      May 31, 1991
  2216.  
  2217.      Although we  have decided  that our program need only support machines
  2218.      that are hardware-compatible with the IBM PC family, this still leaves
  2219.      a variety  of video  environments to  cater for. We must, for example,
  2220.      find out  whether the  host  computer  is  fitted  with  a  colour  or
  2221.      monochrome display  adaptor since  the address of the screen buffer we
  2222.      will be  writing to depends on this. Computers with EGA and VGA cards,
  2223.      moreover, can  switch between  up to  eight display  pages so,  if our
  2224.      program is  running in  one of  these machines, we must make sure that
  2225.      FastPrint sends  its output  to the correct page. Last, but not least,
  2226.      if the  host system  does have  an EGA or VGA we must find out whether
  2227.      the current screen is set to a height of 25, 43 or 50 rows, so that we
  2228.      can format our printing properly.
  2229.      
  2230.      We could,  of course,  code the  instructions that  collect this  data
  2231.      directly into  FastPrint itself.  It is  likely,  however,  that  many
  2232.      other programs  we write will need the same information. Better, then,
  2233.      to make  our  video  system  identification  function  an  independent
  2234.      procedure that can be called by whichever program needs it. This saves
  2235.      us repeating  the same block of code in every screen routine and makes
  2236.      the Toolbox tighter and more efficient.
  2237.      
  2238.                     call VideoType           ; Get video parameters
  2239.      
  2240.      Since VideoType,  as we  have just  decided, is  going to be called by
  2241.      many Toolbox  routines, we  must make sure that the linker can find it
  2242.      when your  program is  built. This  means that  we have  to declare it
  2243.      PUBLIC by putting the following line at the top of the source code.
  2244.      
  2245.                      public  VideoType
  2246.      
  2247.      Note that  versions 5  and 5.1 of MASM have a bug which makes all
  2248.      procedures PUBLIC  by default.  If  you  are  using  either  of  these
  2249.      versions of  the Macro Assembler, therefore, this line is not strictly
  2250.      necessary. However,  because we  cannot rely  on  this  feature  being
  2251.      retained in  future releases,  it is  best to  use an  explicit PUBLIC
  2252.      declaration.
  2253.      
  2254.      VideoType also  needs some space to store the data it collects. Insert
  2255.      the following  lines in  your source file, immediately after the .CODE
  2256.      segment declaration  but before  the  first  PROC  statement.  I  will
  2257.      explain them more fully in a few moments.
  2258.      
  2259.      SnowFlag        db      0               ; Snow prevention flag
  2260.      VideoRam        dw      0B000h          ; Default video segment
  2261.      VideoPort       dw      03BAh           ; Default video status port
  2262.      Param1          label   word
  2263.      Mode            db      7               ; Current screen mode
  2264.      Columns         db      80              ; Current screen width
  2265.      Param2          label   word
  2266.      Rows            db      25              ; Current screen height
  2267.      ActivePage      db      0               ; Current video page
  2268.      
  2269.      Notice that VideoType, like FastPrint itself, is a FAR procedure. This
  2270.      is necessary  if it  is to  be called by routines in seperately-linked
  2271.      
  2272.      The QBNews                                                     Page 37
  2273.      Volume  2, Number  2                                      May 31, 1991
  2274.  
  2275.      modules that may have different Code segments.
  2276.      
  2277.      See the VideoType routine in DISPLAY.ASM.
  2278.      
  2279.      VIDEOTYPE
  2280.      
  2281.      As with  all assembly-language  procedures, it  is  good  practice  to
  2282.      preserve the  contents of  any registers  that will  be changed by the
  2283.      routine and  are not  used to  return data.  Do this  by  pushing  the
  2284.      contents of these registers onto the stack immediately after entry and
  2285.      popping them again just before you return.
  2286.      
  2287.      Our first  task is  to check the current display mode to see if we are
  2288.      running in  a machine with a colour or monochrome monitor. The easiest
  2289.      way is  to call  a service  routine in the computer's BIOS and let the
  2290.      system do  the work  for us. Fortunately there are many such services,
  2291.      grouped by  the hardware  devices that  they interface  with, and with
  2292.      each group  being accessed through a dedicated software interrupt. The
  2293.      Video services are called through Interrupt 16 (10 Hex).
  2294.      
  2295.      To gather the information we want, VideoType issues an INT instruction
  2296.      together with the interrupt number. Interrupt 16 (10 Hex) is a gateway
  2297.      to some  very useful video services. When called with AH set to 15 (0F
  2298.      hex) it  returns with  the current  display mode  in AL, the number of
  2299.      screen columns in AH, and the current video page in BH.
  2300.      
  2301.      An interrupt  is a  signal to the microprocessor that its attention is
  2302.      required. When one occurs, the processor suspends the current task and
  2303.      jumps to  a routine  that is  designed to  deal with  the  event  that
  2304.      triggered off  the interrupt,  this routine  is  called  an  interrupt
  2305.      handler. When  the handler  has done  whatever  is  required,  control
  2306.      returns to  the next instruction in the interrupted task and execution
  2307.      resumes from there. Just like the return from a BASIC subroutine.
  2308.      
  2309.      The 80x86  family of  processors allows  for 256  diffent  interrupts,
  2310.      numbered from  0 to 255. Some are dedicated to hardware devices, every
  2311.      54.936 milliseconds,  for  example,  the  8253  timer  chip  generates
  2312.      interrupt number  8, which  executes a subroutine to update the system
  2313.      clock and date and time flags.
  2314.      
  2315.      Most interrupt  numbers, however, are reserved for software interrupts
  2316.      that can  be generated by programs, using either the assembly-language
  2317.      INT instruction or the QuickBASIC CALL INTERRUPT statement.
  2318.      
  2319.      You call  an interrupt  handler, not by specifying its address, but by
  2320.      supplying the  interrupt number  you require. The actual addresses are
  2321.      stored in  an interrupt  vector table at the very beginning of memory,
  2322.      being written  there by  the initialisation process when your computer
  2323.      is booted-up.  When an interrupt is issued, the processor simply looks
  2324.      up the  table entry for that interrupt number and jumps to the address
  2325.      contained there.  Because different  models of computer have different
  2326.      hardware configurations as well as different versions of DOS and BIOS,
  2327.      the actual  addresses in  the table will vary from machine to machine.
  2328.      But, since  the interrupt  numbers themselves  do not change, programs
  2329.      
  2330.      The QBNews                                                     Page 38
  2331.      Volume  2, Number  2                                      May 31, 1991
  2332.  
  2333.      that use  them are  still portable  between all  computers in  the  PC
  2334.      family.
  2335.      
  2336.      When an  interrupt is  executed, the  processor  makes  the  following
  2337.      actions:
  2338.      
  2339.      1)   The FLAGS  register,  the  current  Code  Segment  (CS)  and  the
  2340.           Instruction Pointer (IP) are saved on the stack.
  2341.      
  2342.      2)   The address of the handling routine is looked up in the Interrupt
  2343.           Vector Table,  starting at  location 0000:0000  in memory.  Since
  2344.           each table  entry is  four bytes  long, the  correct entry can be
  2345.           found by multiplying the interrupt number by four.
  2346.      
  2347.      3)   The segment  and offset address of the interrupt handling routine
  2348.           are loaded into the CS:IP registers, transferring control to that
  2349.           routine.
  2350.      
  2351.      4)   The  code   at  the   handling  routine  is  executed  until  the
  2352.           processor encounters an IRET (RETurn from Interrupt) instruction.
  2353.      
  2354.      5)   The original Instruction Pointer, Code Segment and Flags register
  2355.           are then  restored from the stack and execution proceeds with the
  2356.           instruction that followed the original interrupt call.
  2357.      
  2358.      Figure 1.2     The interrupt  sequence used  on computers  such as the
  2359.                     IBM-PC, which  use the  Intel 80x86  family  of  micro-
  2360.                     processors.
  2361.      
  2362.      On return  from Interrupt 16, VideoType first checks the current video
  2363.      display mode. Notice that we are looking to see if AL contains a value
  2364.      of 7. This is only returned if your computer has a monochrome display.
  2365.      If AL  does equal  7, we can skip the rest of the procedure, since our
  2366.      local variables are set for a monochrome display by default.  Anything
  2367.      other than  7, however,  means that  we have  a  graphics  adaptor  to
  2368.      contend with and must adjust the defaults accordingly.
  2369.      
  2370.      Two variables are involved. The first, labelled VIDEORAM is set to the
  2371.      segment address of the display memory we will be using. This is at Hex
  2372.      0B000 for  mono adaptors  (the default) and 0B800 for colour adaptors.
  2373.      The other  variable is  the number  of the hardware port that controls
  2374.      the video  display. For  mono adaptors this is numbered 3BA (hex). For
  2375.      colour machines the port number must be reset to 3DAh.
  2376.      
  2377.      Notice that  we are accessing local variables through the CS register,
  2378.      using a SEGMENT OVERIDE directive; e.g.
  2379.      
  2380.                     mov  CS:VideoRam,0B800h
  2381.      
  2382.      The reason for this is that the DS register, which is normally used to
  2383.      address data, is still pointing to the calling program's Data Segment.
  2384.      We need to leave DS intact so that we can use it to get at our display
  2385.      string when  we eventually  return to  FastPrint. For now, however, we
  2386.      carry on  and store  the screen  width and  display mode,  which  were
  2387.      
  2388.      The QBNews                                                     Page 39
  2389.      Volume  2, Number  2                                      May 31, 1991
  2390.  
  2391.      returned in  the upper  and lower bytes of AX, in another of our local
  2392.      variables. The  active page, which is in BH, is saved, temporarily, on
  2393.      the stack until we can obtain the screen height to go with it.
  2394.      
  2395.      In computers  fitted with EGA and VGA adaptors the video hardware adds
  2396.      its own  set of  video functions  to the  BIOS video  services. One of
  2397.      these, interrupt  16 sub-function 17/48, returns amongst other things,
  2398.      the information we require; the screen height in rows set in DL.
  2399.      
  2400.      What if  our host  computer doesn't  have an  EGA or  VGA? No  need to
  2401.      worry, calling  an interrupt service that doesn't exist will not cause
  2402.      an error. All that happens is that the function returns with registers
  2403.      unchanged. Since  other video adaptors only allow screen heights of 25
  2404.      rows, if we previously set DL with this number, the correct value will
  2405.      still be  in the  register after the interrupt call. Even if an EGA or
  2406.      VGA isn't  present. Notice, however, that the value we set is actually
  2407.      24. BIOS  routines typically  use a  numbering system  based  on  zero
  2408.      rather than one, so a screen height of 25 rows is returned as 24. This
  2409.      is why  we increment the return value by one, before storing it in its
  2410.      destination variable.
  2411.      
  2412.      One final  thing that  VideoType must do is to detect whether the host
  2413.      computer is using a Colour Graphics Adaptor (CGA). The reason for this
  2414.      is that there is a special problem with CGAs when we write directly to
  2415.      video memory.  I'll go  into more  detail about this later. For now we
  2416.      just need to set a flag to indicate the presence of a CGA.
  2417.      
  2418.      How do  we find out if this computer has a CGA?  Easy. The trick is to
  2419.      find a  video interrupt  service which  only works  on machines fitted
  2420.      with an  EGA or VGA and set an impossible value into one of the return
  2421.      registers. If,  after the  interrupt call has completed, this register
  2422.      is unchanged then an EGA or VGA is not present and we must have a CGA.
  2423.      Remember we  have already  eliminated systems  with Monochrome Display
  2424.      Adaptors (MDA).  Video service  18/16  is  a  suitable  candidate.  It
  2425.      returns a  value of  between 0  and 3  in BL to indicate the amount of
  2426.      memory, in 64K blocks, installed on your video card. VideoType presets
  2427.      BL with  16 (10  hex) before  calling the  interrupt. If this value is
  2428.      still in  BL when the interrupt returns, then we have a CGA to contend
  2429.      with and we must set the SnowFlag accordingly.
  2430.      
  2431.      Before popping  its saved  registers and  returning, VideoType's final
  2432.      task is  to retrieve  all the  information  it  collected  from  local
  2433.      storage. Back  in FastPrint,  we resume  our  task  by  isolating  the
  2434.      information that  is needed next, the current screen dimensions. These
  2435.      are collected  in DX  so that  we can  check them  against  the  start
  2436.      position of  the string  to be  printed, making sure that it is within
  2437.      the screen boundaries.
  2438.      
  2439.                     mov  dh,ah               ; Load screen dimensions
  2440.                     mov  dl,bl               ;    into DX
  2441.      
  2442.      QuickBASIC, conventionally numbers screen rows from 1 to 25 and screen
  2443.      columns from  1 to  80. Since the ROM-BIOS co-ordinate system uses row
  2444.      and  column  numbers  starting  from  zero  we  need  to  convert  our
  2445.      
  2446.      The QBNews                                                     Page 40
  2447.      Volume  2, Number  2                                      May 31, 1991
  2448.  
  2449.      parameters   to base  zero before  we can  start printing. At the same
  2450.      time it would be a good idea to check for legal values.
  2451.      
  2452.      This is where we start collecting the parameters that were passed to
  2453.      us by our caller. First the row co-ordinate:
  2454.      
  2455.                     mov  ax,[bp+12]          ; Get row number
  2456.                     dec  al                  ; Convert to base zero
  2457.                     cmp  al,0                ; Top screen row
  2458.                     jae  Fast_01             ; Jump if not below
  2459.                     xor  al,al               ; Don't go over the top!
  2460.      Fast_01:
  2461.                     cmp  al,dl               ; Bottom row?
  2462.                     jb   Fast_02             ; Go no further
  2463.                     mov  al,dl               ; Substitute maximum
  2464.                     dec  al                  ;    row number
  2465.      
  2466.      Now let's do the same for the column co-ordinate supplied:
  2467.      
  2468.      Fast_02:
  2469.                     mov  bx,[bp+10]          ; Get column number
  2470.                     mov  ah,bl               ;    into AH
  2471.                     dec  ah                  ; Convert to base zero
  2472.                     cmp  ah,0                ; Leftmost column?
  2473.                     jae  Fast_03             ; Jump if not below
  2474.                     xor  ah,ah               ; Don't fall off the screen
  2475.      Fast_03:
  2476.                     cmp  ah,dh               ; Rightmost column?
  2477.                     jb   Fast_04             ; Go no further
  2478.                     mov  ah,dh               ; Substitute maximum
  2479.                     dec  ah                  ;    column number
  2480.      
  2481.      Once we  have a  set of  legal row  and column co-ordinates we need to
  2482.      translate them  into the  actual address  in the  video display buffer
  2483.      where the  data will be written. Since, like VideoType, this is a task
  2484.      that our  Toolbox routines  will have  to perform often, we had better
  2485.      write a seperate procedure to handle it.
  2486.      
  2487.      Fast_04:
  2488.                     call ScreenAddress       ; Calculate target address
  2489.      
  2490.      ScreenAddress, again, must be a FAR procedure so that it can be called
  2491.      from programs  in seperately-linked  modules that  may have  different
  2492.      Code segments.  As always,  we  preserve  on  the  stack  any  working
  2493.      registers that  are not  used to return values. The row and column co-
  2494.      ordinates which  ScreenAddress will  convert into a memory address are
  2495.      supplied in the low and high bytes of AX.
  2496.      
  2497.      See the ScreenAddress routine in DISPLAY.ASM.
  2498.      
  2499.      ADDRESSING MEMORY
  2500.      
  2501.      The 80x86  CPU uses  two registers to fully describe memory addresses.
  2502.      It does  this by  dividing the  absolute address by 16 and storing the
  2503.      
  2504.      The QBNews                                                     Page 41
  2505.      Volume  2, Number  2                                      May 31, 1991
  2506.  
  2507.      result of this calculation in a SEGMENT register. Then another, INDEX,
  2508.      register is  used to hold the remainder, which is called the OFFSET of
  2509.      
  2510.      the object from the start of the segment. The byte at absolute decimal
  2511.      location 753666, for instance, would be addressed as;
  2512.      
  2513.      Segment = (753666 \ 16) = 47104     Offset = (753666 MOD 16) = 2
  2514.      
  2515.      Using hexadecimal  (base 16)  notation, makes  it much simpler to work
  2516.      with segments  and offsets,  since all you need do is shift all digits
  2517.      of the  absolute address,  one place to the right, the rightmost digit
  2518.      falling off to become the offset part of the address:
  2519.      
  2520.        753666 = B8002 (Hex)  -------->  Segment B800 : Offset 0002
  2521.      
  2522.      More conventionally,  this is written by assembly-language programmers
  2523.      as B800:0002.  It is  actually the  memory address  of  the  character
  2524.      displayed in  the second  column of the top row of the screen (if your
  2525.      computer has a color adaptor).
  2526.      
  2527.      Using this method, the PC's 1-megabyte of address space can be divided
  2528.      into 65536  (0 -  FFFFh) possible  segments. Each  segment starts at a
  2529.      different paragraph  boundary (a paragraph is a block of 16 bytes) and
  2530.      contains up to 65536 (0 - FFFFh) different byte addresses. Any segment
  2531.      larger than  16 bytes,  of course,  will  overlap  with  the  segments
  2532.      starting at the next and subsequent paragraph boundaries.
  2533.      
  2534.      To obtain  the address of the position on the screen where our text is
  2535.      to be  printed, ScreenAddress's  first move  is to  copy the  supplied
  2536.      column co-ordinate  into BH.  It then  obtains the  screen  width,  in
  2537.      columns, from the local variable that was previously set by VideoType.
  2538.      Since each  column on the screen takes up two bytes of memory, one for
  2539.      the character  stored there  and the  other  for  the  attribute  that
  2540.      governs how  it is displayed, we now need to multiply the screen width
  2541.      by two  to get  the number of bytes per row. In assembly-language this
  2542.      is easy;  the SHL  instruction shifts all bits of the binary number in
  2543.      BL one position to the left, effectively doubling its value.
  2544.      
  2545.      Since AL  contains the  row number,  we  can now multiply it by BL and
  2546.      get the  byte offset  of this  row. The  MUL instruction  extends  the
  2547.      result of  this calculation  into AX, which is why we moved the column
  2548.      number into  BH out  of the  way. Now we must use SHL again to convert
  2549.      this into  bytes and  add the  result to  AX. We  now have  the target
  2550.      address, offset  from the  beginning of the screen and it only remains
  2551.      for us  to copy  it into  DI, one  of the  index  registers  used  for
  2552.      addressing memory.
  2553.      
  2554.      If PCs  only used  a single  screen page  we could  return right away.
  2555.      However machines with CGA, EGA and VGA cards are capable of displaying
  2556.      multiple pages so we must find which one is currently on the screen.
  2557.      
  2558.      We already  have the page number from VideoType but BIOS makes it even
  2559.      easier by  providing the  actual address  of the current display page,
  2560.      which is what we really want.
  2561.      
  2562.      The QBNews                                                     Page 42
  2563.      Volume  2, Number  2                                      May 31, 1991
  2564.  
  2565.      
  2566.      We don't  need to  use an interrupt call this time. BIOS maintains its
  2567.      own data block at segment 40h in low memory and this contains, amongst
  2568.      many other  things, the  exact information that we're looking for. The
  2569.      address of  the current display page is stored as a two-byte number at
  2570.      offset 4Eh  into  this  block.  Notice,  however,  that  ScreenAddress
  2571.      actually uses  0000:044Eh to  reach it. This is because it is slightly
  2572.      quicker to  clear the ES segment register than it is to load it with a
  2573.      value. The actual memory location remains the same.
  2574.      
  2575.      Figure 1.3    PC Memory map highlighting the BIOS data area in low RAM
  2576.      
  2577.      Once we  have the page offset all that remains is to add it to the row
  2578.      and column  offset that is already in DI. VideoType has already stored
  2579.      the video  segment and port address for us so we just need to retrieve
  2580.      these parameters before returning to FastPrint.
  2581.      
  2582.      The result of all this register juggling is that we now have the ES:DI
  2583.      register pair  pointing to  the address  in memory  where output is to
  2584.      start. DX  is also  loaded with  the address  of the  video controller
  2585.      port. Now we're ready to find the string to display.
  2586.      
  2587.      What QuickBASIC  passes when  a string is specified as parameter to an
  2588.      external procedure,  is a  pointer to  a STRING DESCRIPTOR in the Data
  2589.      Segment. This  is a  four-byte block  of data  of which  the first two
  2590.      bytes are  the string length. In QuickBASIC strings may be up to 32767
  2591.      bytes in length:
  2592.      
  2593.      Figure 1.4     Structure of the String Descriptor passed by QuickBASIC
  2594.      
  2595.      The second two bytes of the string descriptor contain a pointer to the
  2596.      first character  of the  string itself.  This is  an  offset  address,
  2597.      relative to  the start  of DGROUP,  QuickBASIC's default Data Segment.
  2598.      This is  the  address  that  is  returned  by  the  SADD  function  in
  2599.      QuickBASIC. When used with a string, VARPTR returns the address of the
  2600.      string descriptor instead.
  2601.      
  2602.      If you  are using  Microsoft's BASIC 7 Professional Development System
  2603.      then the  method of  passing strings  is  rather  different.  See  the
  2604.      sidebar for more details.
  2605.      
  2606.      Before going any further, we should check that there is a string to be
  2607.      printed. If  the first  two-bytes of the string descriptor evaluate to
  2608.      zero, a null string has been passed so there is no point in proceeding
  2609.      further. Consequently we set the AX register to an error code and jump
  2610.      to the  exit. It  is good  practice to  return a  code indicating  the
  2611.      success or  failure of an operation when we leave, even if the calling
  2612.      program will  not read  it.  Most  DOS  applications  return  such  an
  2613.      ERRORLEVEL as a matter of course.
  2614.      
  2615.      Well the  string is  there, so  we can  load its address, which is the
  2616.      second two  bytes of  the string  descriptor,  into  our  other  Index
  2617.      Register, SI.
  2618.      
  2619.      
  2620.      The QBNews                                                     Page 43
  2621.      Volume  2, Number  2                                      May 31, 1991
  2622.  
  2623.                     mov  bx,[bp+8]           ; Index to string descriptor
  2624.                     mov  cx,[bx]             ; Get string length
  2625.                     cmp  cx,0                ; Make sure it isn't
  2626.                     ja   Fast_05             ;    a null string
  2627.                     mov  ax,1                ; If so set Error code
  2628.                     jmp  short Fast_07       ;    and abort
  2629.      Fast_05:
  2630.                     mov  si,[bx+2]           ; DS:SI==> string data
  2631.                     mov  ax,[bp+6]           ; Get display attribute
  2632.                     xchg ah,al               ;    into AH
  2633.                     cld                      ; Clear direction flag
  2634.      
  2635.      This is  a good  opportunity to  get the  final parameter, the display
  2636.      attribute we  are to  use,  into  the  AH  register.  The  CLD  (Clear
  2637.      Direction  Flag)   instruction  ensures  that  any  subsequent  string
  2638.      manipulation instructions  move data  forwards in  memory. Now that we
  2639.      are ready  to start  printing, the  processor registers  are set up as
  2640.      follows:
  2641.      
  2642.      Segment Registers:  ES   points to the current video segment.         
  2643.                          DS   points to the calling program's DATA segment.
  2644.      
  2645.      Index Registers:    DI   points to the offset address, relative to ES,
  2646.                               where the string will be copied to.
  2647.                          SI   points to the beginning of our source string,
  2648.                               relative to the DS register.
  2649.                          
  2650.      General Registers:  DX   contains the video status port address.
  2651.                          CX   contains the length of the source string.
  2652.                          AH   contains the display attribute to be given to
  2653.                               each output character.
  2654.      
  2655.      The last section of code is a simple loop that copies each byte of the
  2656.      source string  to its  destination address in video memory. Instead of
  2657.      using a  MOV instruction  to copy  each byte of the string into the AL
  2658.      register before transferring it to the screen, we use another assembly
  2659.      instruction, LODSB.
  2660.      
  2661.      Fast_06:
  2662.                     lodsb                    ; Get a byte from the string
  2663.      
  2664.      LODSB is one of a set of string manipulation primatives built into the
  2665.      Intel family  of microprocessors.  Why they  are called  'primitive' I
  2666.      don't know.  They are,  in  fact,  extremely  powerful.  In  just  one
  2667.      statement, LOSB  will load a byte from the address pointed to by DS:SI
  2668.      into the  AL register  and then automatically increment SI to point to
  2669.      the next byte. If we were to prefix it with a REP instruction it would
  2670.      repeat the  whole operation  for the number of times that the value in
  2671.      CX is set to. This, as you can see, is just the thing for loops.
  2672.      
  2673.      In fact,  if we didn't have to cater for systems with CGA video cards,
  2674.      we could  do the  remainder of  the job  in just one line. LODSB has a
  2675.      companion instruction,  MOVSB, which,  as it's name implies, moves the
  2676.      byte at  DS:SI to  a destination  address pointed to by ES:SI. In this
  2677.      
  2678.      The QBNews                                                     Page 44
  2679.      Volume  2, Number  2                                      May 31, 1991
  2680.  
  2681.      case both of the index registers, SI and DI, are incremented ready for
  2682.      the next  byte to  be transfered. Like LODSB, MOVSB takes a REP prefix
  2683.      and, since  we already  have the  length of our string in CX, all that
  2684.      would be necessary is to enter the instruction ....
  2685.      
  2686.                     rep  movsb               ; Shift the whole string
  2687.      
  2688.      ... and the job would be done.
  2689.      
  2690.      But we  do have to contend with CGA cards so our task is a little more
  2691.      complicated and,  since it is one that we will need to repeat in other
  2692.      programs, we had better do it in a sub-routine.
  2693.      
  2694.                     call ScreenWrite         ; Write a byte and attribute
  2695.                     loop Fast_06             ; Repeat for each character
  2696.      
  2697.      See the ScreenWrite routine in DISPLAY.ASM.
  2698.      
  2699.      The problem  with CGAs  occurs only  when we  write directly  to video
  2700.      memory. If  the 6845 CRT Controller attempts to fetch a character from
  2701.      the screen  buffer whilst data is being written to that same location,
  2702.      the resulting  interference will cause 'snow' or glitches to appear on
  2703.      the screen.  We can prevent this happening by making sure that we only
  2704.      output to the display when the 6845 is not reading from it.
  2705.      
  2706.      Fortunately we  do not have to wait long, since every 12 microseconds,
  2707.      the 6845  performs what is known as a horizontal retrace. During this,
  2708.      time the  controller is  not doing  any reading  so it is safe for our
  2709.      program to write to the display.
  2710.      
  2711.      We can  detect when a horizontal retrace is in progress by testing bit
  2712.      zero of  the video  adaptor status  port, its  address is  now in  DX,
  2713.      remember?  If this bit is set then a retrace is under way. In practice
  2714.      we let  any current  retrace complete  and wait for the next to begin,
  2715.      before moving data. This ensures that we have we a full retrace period
  2716.      in which  to place  the character and attribute byte into their proper
  2717.      buffer addresses.
  2718.      
  2719.      Computers with monochrome adaptors and those with more modern versions
  2720.      of the  CGA, do  not experience  'snow' problems  and, if you are sure
  2721.      that you will only be using FastPrint in such systems, you are welcome
  2722.      to leave  out the  routine.  Me, I wouldn't bother. Using it ensures a
  2723.      good clean  display, no  matter which computer you use the program in,
  2724.      and the  increase in  processing time does not slow your programs down
  2725.      enough to be noticed. It is a lot faster than PRINT, at any rate.
  2726.      
  2727.      All that  remains, now that our string has been output to the display,
  2728.      is to  tidy up  the stack  and return safely to the QuickBASIC program
  2729.      that called us.
  2730.      
  2731.      First we  recover all  the registers  that were pushed on entry to the
  2732.      routine.
  2733.      
  2734.                     xor  ax,ax               ; Report success
  2735.      
  2736.      The QBNews                                                     Page 45
  2737.      Volume  2, Number  2                                      May 31, 1991
  2738.  
  2739.      Fast_07:
  2740.                     pop  di                  ; Clean up the stack
  2741.                     pop  si
  2742.                     pop  es
  2743.                     pop  bp
  2744.      
  2745.      The final  return instruction  must  adjust  the  stack  so  that  any
  2746.      parameters that  were originally passed are now discarded. Our routine
  2747.      received four parameters, each of which took up two bytes of stack, so
  2748.      we issue  a RET  8 to  decrement the  Stack Pointer by eight, ensuring
  2749.      that the correct return address is popped back into CS:IP.
  2750.      
  2751.                     ret  8                   ; Return to Quick BASIC
  2752.      FastPrint      endp
  2753.      
  2754.                     end
  2755.      
  2756.      Last of  all, don't  forget to  tell the  assembler where  the current
  2757.      procedure and program end.
  2758.      
  2759.      Here is  the full listing of FastPrint again. If you type it in, don't
  2760.      forget to  include the  code for  the three  procedures ScreenAddress,
  2761.      ScreenWrite and  VideoType in their proper places before the final END
  2762.      directive. Notice that, since all the routines in the file are related
  2763.      to the  video display, I have given it the name DISPLAY.ASM. I suggest
  2764.      that you  use this  name as  well. We  are going  to add  to it in the
  2765.      ensuing chapters.
  2766.      
  2767.      ASSEMBLY AND LINKING
  2768.      
  2769.      Since all the procedures we have written so far are concerned with the
  2770.      video display,  I propose  that we  call the source file that contains
  2771.      them DISPLAY.ASM.  Save it  as such  and then  assemble it  using  the
  2772.      following command:
  2773.      
  2774.                   MASM /V/W2/Z display;
  2775.           
  2776.      The /V  (VERBOSE) switch  instructs the assembler to report statistics
  2777.      such as the number of program lines and symbols processed.
  2778.      
  2779.      The /W2  switch sets  the assembler's  WARNING level  to maximum. This
  2780.      instructs it to report statements that may result in inefficient code,
  2781.      as well  as actual  errors. It  reports, for  example, when  you  have
  2782.      issued a normal JMP instruction where a short jump will do. This helps
  2783.      you write tighter code.
  2784.      
  2785.      The /Z  switch directs MASM to list any lines, where errors are found,
  2786.      on the screen. Another help in debugging.
  2787.      
  2788.      If you  use an  assembler  other  than  MASM,  of  course,  the  above
  2789.      instructions do  not apply.  In this case consult your own assembler's
  2790.      documentation.
  2791.      
  2792.      If the  assembly is  successful, you  will have  a file,  DISPLAY.OBJ,
  2793.      
  2794.      The QBNews                                                     Page 46
  2795.      Volume  2, Number  2                                      May 31, 1991
  2796.  
  2797.      containing the  assembled object  code. This  is all ready for linking
  2798.      directly to compiled Quick BASIC programs which are to be run from the
  2799.      DOS command line. You can link it with the instruction:
  2800.      
  2801.           LINK yourprog DISPLAY;
  2802.           
  2803.      (where 'yourprog' is the name of your own program)
  2804.           
  2805.      If you  want to  use FastPrint in the QuickBASIC environment, you will
  2806.      also have to include it in a Quick Library. Use the Linker for this as
  2807.      well, the command is:
  2808.      
  2809.           LINK /QU DISPLAY,,,BQLB45.LIB;
  2810.           
  2811.      BQLB45.LIB is  the standard  library interface  module  supplied  with
  2812.      QuickBASIC 4.5,  (if you are using the Extended QuickBASIC which comes
  2813.      with  MicroSoft's   BASIC  7  PDS,  the  equivalent  module  is  named
  2814.      QBXQLB.LIB). Whichever  one you  use, make  sure that  it  is  in  the
  2815.      current directory when you issue the LINK command. You should now have
  2816.      a file DISPLAY.QLB.
  2817.      
  2818.      If you've  got this  far, you  will, no  doubt be  anxious to  try out
  2819.      FastPrint in  a QuickBASIC program. Let's start with a small one which
  2820.      draws coloured  boxes on  the screen,  just to test that it is working
  2821.      properly. We'll call it PANELS.BAS.
  2822.      
  2823.      Start up QuickBASIC with the following ...
  2824.      
  2825.           QB PANELS.BAS /L DISPLAY.QLB
  2826.                
  2827.      The first  thing to  do is  to declare  our  routine  as  an  external
  2828.      procedure. We won't be expecting it to return any value, so we declare
  2829.      it as a SUBprogram rather than a FUNCTION.
  2830.      
  2831.      DECLARE SUB FastPrint (BYVAL Row%, BYVAL Col%, Text$, BYVAL Attr%)
  2832.      
  2833.      Make sure  that all  the parameters  are correctly  listed and  of the
  2834.      correct type. Integers for the Row, Column and Attribute arguments and
  2835.      a string for the text which we will be supplying.
  2836.      
  2837.      Okay, was that fast enough for you?
  2838.      
  2839.      What you  have done,  in effect,  is to  add your own extension to the
  2840.      QuickBASIC language.  Provided that the procedure is properly declared
  2841.      at the  top of  your program,  and the  object file is linked or in an
  2842.      attached Quick  Library, you  can use FastPrint as easily as any other
  2843.      QuickBASIC statement  or function.  You don't  even have to preface it
  2844.      with the CALL directive, nor do you need to enclose the parameter list
  2845.      with parentheses.
  2846.      
  2847.      If you  are not sure how to work out proper values for the colours and
  2848.      attributes which  you want  your display to have, Appendix A goes into
  2849.      this in  some detail.  By all  means experiment,  your taste  is  very
  2850.      likely different  from mine.  You may  even want to write special SUBS
  2851.      
  2852.      The QBNews                                                     Page 47
  2853.      Volume  2, Number  2                                      May 31, 1991
  2854.  
  2855.      for commonly-used attributes, for instance ...
  2856.      
  2857.           SUB RevPrint (Row%, Column%, Text$) STATIC
  2858.               FastPrint Row%, Column%, Text$, 112
  2859.           END SUB
  2860.           
  2861.      ... calls  FASTPRINT with  the attribute  set for  REVERSE VIDEO text,
  2862.      Black characters  on a  White background (actually Green on monochrome
  2863.      monitors.
  2864.      
  2865.           SUB NormalPrint (Row%, Column%, Text$) STATIC
  2866.               FastPrint Row%, Column%, Text$, 7
  2867.           END SUB
  2868.           
  2869.      ... calls  FASTPRINT with the attribute set to normal video. Just like
  2870.      PRINT in fact, only faster.
  2871.      
  2872.      By the  way, what  did all  those panels  remind you of? That's right,
  2873.      WINDOWS. Well  you'll just have to wait. The Windows will be opened in
  2874.      a future article.
  2875.      ----------------------------------------------------------------------
  2876.  
  2877.      ROM-BIOS Video Services
  2878.      
  2879.      ROM-BIOS provides  services which  enable us  to determine the current
  2880.      display mode,  select the video page to which output will be directed,
  2881.      find the  current cursor  position and  the  character  and  attribute
  2882.      underneath it,  and to  selectively scroll  a specified  area  of  the
  2883.      display. They  are accessed by loading the AH register with the number
  2884.      of the  service required,  and then issuing interrupt 16 (10 Hex). You
  2885.      may have  to preset  values into  other registers,  depending upon the
  2886.      service being called.
  2887.      
  2888.      Unless used  for returned  values, the  contents of  the BX, CX and DX
  2889.      registers are  preserved across  these calls.  Likewise,  the  segment
  2890.      registers will  be returned  intact. You  should not  assume, however,
  2891.      that the contents of other registers will be maintained. Remember also
  2892.      that the  system, used  by the  BIOS for  numbering  screen  rows  and
  2893.      columns, differs  from QuickBASIC  in that  the x/y co-ordinate of the
  2894.      top-left corner of the screen is regarded as being 0,0 instead of 1,1.
  2895.      
  2896.      ----------------------------------------------------------------------
  2897.      INT 10h        Get current video display mode.             all systems
  2898.      
  2899.      Call with:     AH = 0Fh (15 decimal)         
  2900.      
  2901.      Returns:       AL = display mode (see table below)
  2902.                     AH = screen width in columns
  2903.                     BH = cureent display page
  2904.      
  2905.      Mode Resolution  Colours Screen    Mode Resolution  Colours Screen    
  2906.           
  2907.      ----------------------------------------------------------------------
  2908.      0    40 x 25        2    text      1    40 x 25        2    text
  2909.      2    80 x 25        2    text      3    80 x 25        16   text
  2910.      4    320 x 200      4    graphics  5    320 x 200      4    graphics
  2911.      
  2912.      The QBNews                                                     Page 48
  2913.      Volume  2, Number  2                                      May 31, 1991
  2914.  
  2915.      6    640 x 200      2    graphics  7    80 x 25        2    text
  2916.      8    160 x 200      16   graphics  9    320 x 200      16   graphics
  2917.      10   640 x 200      4    graphics  13   320 x 200      16   graphics
  2918.      14   640 x 200      16   graphics  15   640 x 350      2    graphics
  2919.      16   640 x 350      16   graphics  17   640 x 480      2    graphics
  2920.      18   640 x 480      16   graphics  19   320 x 200      256  graphics
  2921.      ----------------------------------------------------------------------
  2922.      
  2923.      Computers fitted  with the  Monochrome Display Adaptor (MDA) will only
  2924.      support mode 7, (80 x 25 character text).
  2925.      
  2926.      Modes 4 and 6 correspond to QuickBASIC's SCREEN 1 and SCREEN 2.
  2927.      
  2928.      Modes 8, 9 and 10 are only available on the IBM PCjr (and Tandy 1000).
  2929.      
  2930.      Modes 13  and up are only available on machines fitted with EGA or VGA
  2931.      adaptors, Mode  16 supports either 4 or 16 colours, depending upon the
  2932.      amount of video memory available.
  2933.      ROM-BIOS VIDEO SERVICES
  2934.      
  2935.      ----------------------------------------------------------------------
  2936.      INT 10h        Get Font information                EGA, VGA, MCGA only
  2937.      
  2938.      Call with:     AH = 11h  (17 decimal)
  2939.                     AL = 30h  (48 decimal)
  2940.                     BH = 00h  for default character set.    
  2941.      
  2942.      Returns:       CX =      point size (number of bytes per character)
  2943.                     DL =      screen height in rows - 1
  2944.                     ES:BP =>  address of character definition table
  2945.      
  2946.      Note:          information  about   the  alternative   character  sets
  2947.                     provided by  your video  adaptor is obtained by loading
  2948.                     BH with  the appropriate  font number.  See your EGA or
  2949.                     VGA reference manual for more details.
  2950.      
  2951.      ----------------------------------------------------------------------
  2952.      INT 10h        Get Configuration information             EGA, VGA only
  2953.      
  2954.      Call with:     AH = 12h  (18 decimal)
  2955.                     BL = 10h  (16 decimal)
  2956.      
  2957.      Returns:       BH =      display type (0 = colour, 1 = monochrome)
  2958.                     BL =      video memory installed
  2959.                               (0 = 64K,  1 = 128K,  2 = 192K,  3 = 256K)
  2960.                     CX =      Adaptor feature bits and DIP switch settings
  2961.      
  2962.      Notes:         BL will  still return  a value  of 3  even if more than
  2963.                     256K of video memory is installed. 
  2964.      
  2965.      for more  information about  the meaning  of the  value returned in CX
  2966.      consult your EGA or VGA reference manual.
  2967.      ----------------------------------------------------------------------
  2968.  
  2969.      
  2970.      
  2971.      The QBNews                                                     Page 49
  2972.      Volume  2, Number  2                                      May 31, 1991
  2973.  
  2974.      Using FastPrint with BASIC 7
  2975.  
  2976.      If you intend using FastPrint with programs compiled under the BASIC 7
  2977.      Professional Development System then a few changes are necessary. This
  2978.      is because  BASIC 7  uses Far  Strings which  gives strings  a  memory
  2979.      segment of  their own instead of putting them into DGROUP, the default
  2980.      Data Segment pointed to by DS.
  2981.      
  2982.      To enable  you to find the address of a far string, BASIC 7 provides a
  2983.      built-in function  called StringAddress.  This must be declared at the
  2984.      head of your source code file between the .MODEL and .CODE directives,
  2985.      so that  the Linker  can fix-up  references to  the function when your
  2986.      program is built:
  2987.      
  2988.                      extrn   StringAddress: proc
  2989.      
  2990.      This done,  you should  rewrite the  lines between labels Fast_04: and
  2991.      Fast_06: as follows:
  2992.      
  2993.      Fast_04:
  2994.                      push    ax              ; Save display co-ordinates
  2995.                      mov     ax,[bp+8]       ; Index to string descriptor
  2996.                      push    ax              ; Call BASIC for
  2997.                      call    StringAddress   ;    string parameters
  2998.                      pop     bx              ; Recover co-ordinates
  2999.                      jcxz    Fast_06         ; Abort if a null string
  3000.                      mov     ds,dx           ; String segment to DS
  3001.                      mov     si,ax           ; DS:SI==> string data
  3002.                      mov     ax,bx           ; Co-ordinates to AX
  3003.                      call    ScreenAddress   ; Calculate target address
  3004.                      mov     ax,[bp+6]       ; Get display attribute
  3005.                      xchg    ah,al           ;    into AH
  3006.                      cld                     ; Clear direction flag
  3007.      
  3008.      Notice that,  just like  QuickBASIC 4.5,  we still  have to obtain the
  3009.      address of the string descriptor from our argument list. With BASIC 7,
  3010.      however, we  pass it  on to  StringAddress by pushing it back onto the
  3011.      stack before  calling this  function. On return, BASIC 7 will have set
  3012.      our registers as follows:
  3013.      
  3014.                     DX  =     segment of target string
  3015.                     CX  =     length of target string
  3016.                     AX  =     offset of target string
  3017.      
  3018.      The explanation  in the  BASIC 7  manual and on-line Help implies that
  3019.      you need to call a seperate function, StringLength, to find the length
  3020.      of the  string. In practice this is not necessary since StringAddress,
  3021.      itself, returns this information in CX.
  3022.      
  3023.      **********************************************************************
  3024.      Christy Gemmell resides in England and was the major author of the
  3025.      Waite Group book QuickBASIC Bible. Christy also has a shareware
  3026.      called the Assembly-Language Toolbox for QuickBASIC. Christy can be
  3027.      reached in care of this newsletter.
  3028.      **********************************************************************
  3029.      
  3030.      The QBNews                                                     Page 50
  3031.      Volume  2, Number  2                                      May 31, 1991
  3032.  
  3033.  
  3034.      ----------------------------------------------------------------------
  3035.                         P o w e r   P r o g r a m m i n g
  3036.      ----------------------------------------------------------------------
  3037.  
  3038.      An Improved Cloning Algorithm by Larry Stone
  3039.      
  3040.         Who ever said that there is no such thing as  a  bug  free  program
  3041.      must have been very familiar with my work.   To my chagrin, the code I
  3042.      wrote for "The QBNews", Vol. 1, No. 3, concerning programs that  clone
  3043.      to themselves,  contained a bug that could hang your system.   In  the
  3044.      endeavor to wipe the egg off of my face, I present a new function that
  3045.      corrects this error and, as a side benefit,  executes faster and,  for
  3046.      those of you who use the PDQ library, is compatible with PDQ.
  3047.      
  3048.         The function, SearchEXE$, as originally published, used a DO...LOOP
  3049.      terminated with the instruction, "DO WHILE NOT EOF(1)".   In the event
  3050.      that the program does not contain the  special  marker  in  the  EXE's
  3051.      token area (refer to QBNWS103), the loop  would  execute  indefinitely
  3052.      because the EOF is never read with files opened in  the  BINARY  mode.
  3053.      The solution is one line of code:
  3054.      
  3055.                    IF Bytes + Portion& >= FiSize& THEN EXIT DO
  3056.      
  3057.         The other major change presented here is the  substitution  of  GET
  3058.      for INPUT$().   The GET will operate faster and  will  make  the  code
  3059.      compatible with Crescent's PDQ.
  3060.      
  3061.      FUNCTION SearchEXE$ (FileName$, Key$, DatLen) STATIC
  3062.      
  3063.      'The Bytes% variable is the number of bytes to read. If your program is
  3064.      'less than 16000 bytes then this routine adjusts accordingly.  Also, if
  3065.      'a 16000 byte "GET" cuts the marker in two, you don't have to worry
  3066.      'about it because we adjust the file pointer accordingly.
  3067.      
  3068.      Bytes = 16000           '16000 bytes to read with each pass.
  3069.      BytesToData& = 0        'Initialize it to zero.
  3070.      Portion& = 1            'Initialize to file's 1st byte.
  3071.      CountToKey = 0          'The count to Key$ location.
  3072.      
  3073.      Handle = FREEFILE       'Get a number for the file.
  3074.      OPEN FileName$ FOR BINARY AS #Handle
  3075.      FiSize& = LOF(Handle)
  3076.      
  3077.      DO
  3078.      
  3079.         '---- 16000 bytes is to many so, reduce it.
  3080.         IF Bytes > FiSize& THEN Bytes = FiSize&
  3081.      
  3082.         '---- If Portion& + Bytes is greater than FiSize&, reduce Bytes.
  3083.         IF Bytes + Portion& > FiSize& THEN Bytes = FiSize& - Portion&
  3084.      
  3085.         '---- Point into the file (Portion&) and input "Bytes".
  3086.         A$ = SPACE$(Bytes)         'Configure the string to "Bytes" length.
  3087.         SEEK #Handle, Portion&     'SEEK to the portion.
  3088.      
  3089.      The QBNews                                                     Page 51
  3090.      Volume  2, Number  2                                      May 31, 1991
  3091.  
  3092.         GET #Handle, , A$          'Using GET works with PDQ & is faster.
  3093.      
  3094.         CountToKey = INSTR(A$, Key$)               'Is Key in A$?
  3095.         IF CountToKey THEN                         'Yes, we found the Key!
  3096.      
  3097.            '---- Calculate were the data is located.
  3098.            BytesToData& = Portion& + CountToKey + LEN(Key$) - 1
  3099.      
  3100.            A$ = SPACE$(DatLen)             'Configure the string to DatLen.
  3101.            SEEK #Handle, BytesToData&      'SEEK to the data location.
  3102.            GET #Handle, , A$               'Now get the data.
  3103.            SearchEXE$ = A$                 'Set the function.
  3104.            CLOSE #Handle                   'Close the file.
  3105.            A$ = ""                         'A little garbage collection
  3106.      
  3107.            EXIT FUNCTION
  3108.         END IF
  3109.      
  3110.         '---- We've reached the end of the file and did not find our
  3111.         '     Marker$.  This prevents an endless loop.
  3112.         IF Bytes + Portion& >= FiSize& THEN EXIT DO
  3113.      
  3114.         '---- We subtract the key length in case it was split by our GET.
  3115.         Portion& = Bytes + Portion& - LEN(Key$)
  3116.      
  3117.      LOOP
  3118.      
  3119.      CLOSE #Handle
  3120.      PRINT "Error. Could not find key!"
  3121.      END
  3122.      
  3123.      END FUNCTION
  3124.      
  3125.  
  3126.  
  3127.  
  3128.  
  3129.  
  3130.  
  3131.  
  3132.  
  3133.  
  3134.  
  3135.  
  3136.  
  3137.  
  3138.  
  3139.  
  3140.  
  3141.  
  3142.  
  3143.  
  3144.  
  3145.  
  3146.      The QBNews                                                     Page 52
  3147.      Volume  2, Number  2                                      May 31, 1991
  3148.  
  3149.  
  3150.  
  3151.      ----------------------------------------------------------------------
  3152.                        N e w   a n d   N o t e w o r t h y
  3153.      ----------------------------------------------------------------------
  3154.  
  3155.      Custom Control Factory for Microsoft Visual Basic by Desaware
  3156.      
  3157.      Desaware has announced the Custom Control Factory version 1.0, a
  3158.      companion product to Microsoft Visual Basic which permits the user to
  3159.      create a rich variety of custom button controls without the need for
  3160.      special programming.
  3161.      
  3162.      The Custom Control Factory has been developed to bridge the gap
  3163.      between the standard controls included with Visual Basic and custom
  3164.      controls which require advanced programming with the Windows Software
  3165.      Development Kit and Control Development Kit for Visual Basic. Custom
  3166.      Control Factory buttons are created interactively from within the
  3167.      Visual Basic design environment without the need for special
  3168.      programming. A runtime version of the product can be distributed with
  3169.      compiled Visual Basic applications without further licence fees.
  3170.      
  3171.      The Custom Control Factory version 1.0, along with over fifty sample
  3172.      controls, is being introduced at only $48 and will be available
  3173.      immediately after the release of Visual Basic version 1.0.
  3174.      
  3175.      You can contact Desaware by calling 408-377-4770.
  3176.      
  3177.      
  3178.      If you have a new product or an upgrade to an existing product you
  3179.      would like announced in The QBNews, please send info to:
  3180.      
  3181.      The QBNews
  3182.      P.O. Box 507
  3183.      Sandy Hook, CT 06482
  3184.      
  3185.  
  3186.  
  3187.  
  3188.  
  3189.  
  3190.  
  3191.  
  3192.  
  3193.  
  3194.  
  3195.  
  3196.  
  3197.  
  3198.  
  3199.  
  3200.  
  3201.  
  3202.  
  3203.  
  3204.  
  3205.      The QBNews                                                     Page 53
  3206.      Volume  2, Number  2                                      May 31, 1991
  3207.  
  3208.  
  3209.  
  3210.      ----------------------------------------------------------------------
  3211.                             F u n   a n d   G a m e s
  3212.      ----------------------------------------------------------------------
  3213.  
  3214.      ASCII Art -- A Piece of Computer History by Charles Graham
  3215.      
  3216.      
  3217.      In The Beginning ...
  3218.      
  3219.         folks created ASCII Art.  Before ANSPAINT, THEDRAW, GIFs and all
  3220.      the rest, before color and sound and animation techniques, before CGA,
  3221.      EGA and VGA, people used COPY CON, EDLIN or their favorite text editor
  3222.      to produce art similar to the typewriter art of earlier, pre-PC
  3223.      generations.
  3224.      
  3225.         Over a number of years, I have collected 12 of these pictures from
  3226.      bulletin boards and individuals.  For all I know, these are the only
  3227.      examples of ASCII art that remain.  Evidently, most ASCII artists were
  3228.      people who liked to draw full-figured nude women.  I have never seen
  3229.      an ASCII picture of anything but this particular subject.  To the best
  3230.      of my knowledge and belief, all of the pictures that come with this
  3231.      collection are of unknown origin and are in the public domain.
  3232.      
  3233.         I have always felt these low-tech creations were worth saving if
  3234.      only for historic or nostalgic purposes -- like the early efforts of
  3235.      cave dwellers when they drew stick figures of buffalo on the walls of
  3236.      their abode.
  3237.      
  3238.         ASCII art is created by using lower-ASCII characters starting with
  3239.      ASCII 32 (the blank or space character).  To my knowledge, no
  3240.      upper-ASCII (8th bit on) graphics or foreign language characters were
  3241.      ever used.
  3242.      
  3243.         Even using this limited palette, however, viewing and printing the
  3244.      pictures always presented certain problems.  When using the DOS TYPE
  3245.      command, only a small fraction of the work is on screen at any moment,
  3246.      and the work is badly out of proportion.  Printing them can also be
  3247.      tricky because the default values of most printers (a horizontal pitch
  3248.      of 10 characters per inch and a vertical pitch of 6 lines per inch)
  3249.      produces images that are too long and contain too much white space.
  3250.      So I created ASCIIART.BAS
  3251.      
  3252.      What Is ASCIIART.BAS?
  3253.      
  3254.         ASCIIART solves the on-screen viewing problems by translating the
  3255.      characters that make up an ASCII picture into color attributes.  It
  3256.      uses these attributes to put pixels on your screen.  The resulting
  3257.      image is perhaps closer to the way the artist originally envisioned
  3258.      his subject then the DOS TYPE command could ever allow.  On EGA
  3259.      systems, the picture is small but high- resolution and may contain up
  3260.      to five colors plus black.  On CGA systems, the picture is of medium
  3261.      size and resolution and may contain up to three colors plus black.
  3262.      ASCIIART does not support monochrome systems.
  3263.      
  3264.      
  3265.      The QBNews                                                     Page 54
  3266.      Volume  2, Number  2                                      May 31, 1991
  3267.  
  3268.      Color Selection
  3269.      
  3270.         I began the color selection process with what I thought was a
  3271.      logical assumption:  ASCII artists would instinctively choose
  3272.      characters with more "weight" to denote shading and less "weight" to
  3273.      denote highlights.  I defined "weight" as the amount of ink that hits
  3274.      the paper when a particular character is printed.
  3275.      
  3276.         I put my dot matrix printer into draft mode and printed all the
  3277.      printable characters.  I used a magnifying glass and inspected each
  3278.      one.  I counted and recorded the number of dots used to print each
  3279.      character and divided them into six "weight" groups.
  3280.      
  3281.         Then through trial and error I began associating different colors
  3282.      with different "weight" groups until I began to get a pattern that
  3283.      "worked."  Further refinement and tinkering developed the pattern that
  3284.      comes hard coded in ASCIIART.BAS.
  3285.      
  3286.         Because different ASCII artists favored different characters to
  3287.      draw with, the method by which ASCIIART assigns color attributes to
  3288.      characters is a compromise.  However, for the twelve ASCII pictures I
  3289.      have managed to collect, I believe it is the best compromise available.
  3290.      
  3291.         Users who want to experiment with color selection can easily do so
  3292.      by altering the DATA statements at the end of ASCIIART's main module
  3293.      as well as the FOR/NEXT loops in SUB loadarray.  You can come up with
  3294.      some rather garish renditions without much effort.
  3295.      
  3296.      Printing The Pictures
  3297.      
  3298.         ASCIIART also assists you in making a decent looking copy of an
  3299.      ASCII picture on your printer.  The printer parameters that I have
  3300.      found work best are:
  3301.      -- Condensed Print, i.e., a horizontal pitch of 17 characters per
  3302.         inch or close to it
  3303.      -- Near Letter Quality (NLQ or double-strike) printing as opposed
  3304.         to Draft Quality printing
  3305.      -- Uni- as opposed to Bi-directional printing, and
  3306.      -- a vertical pitch of 7/72nds of an inch, i.e., approximately 10
  3307.         1/4 lines per inch.
  3308.      
  3309.      To set these parameters on IBM printers, the following ASCII
  3310.      characters need to be sent:
  3311.      -- ASCII 15             (to enter condensed mode)
  3312.      -- ASCII 27 and 71      (to enter NLQ mode)
  3313.      -- ASCII 27, 85 and 49  (to enter unidirectional mode)
  3314.      -- ASCII 27, 65and 7    (to store a vertical pitch of 7/72")
  3315.      -- ASCII 27 and 50      (to begin using the stored vertical pitch).
  3316.      
  3317.         To produce the best possible rendition, ASCIIART will automatically
  3318.      send the correct control codes and escape sequences to supported
  3319.      printers before printing the pictures.  And it allows those who don't
  3320.      want to send any control codes or escape sequences not to do so.
  3321.      
  3322.      
  3323.      The QBNews                                                     Page 55
  3324.      Volume  2, Number  2                                      May 31, 1991
  3325.  
  3326.         ASCIIART also invites the owners of non-supported printers to enter
  3327.      their own control codes and escape sequences to set the correct
  3328.      printer parameters.  Entering "C" (for Custom) at the printer
  3329.      selection screen will allow such users to do this.
  3330.      
  3331.      Printing Other Pictures
  3332.      
  3333.         ASCIIART has a feature that will allow you to print or view other
  3334.      ASCII pictures, should you come across one or care to create one.
  3335.      Place the picture in the same directory as all the other files
  3336.      included with this collection and name it OTHER.ASC.  Then, when you
  3337.      are prompted for the name of the picture, enter the name OTHER.  You
  3338.      can even view your word processing documents this way -- if you'd like!
  3339.      
  3340.      In Closing
  3341.      
  3342.         To help keep this edition of The QBNews at a reasonable size, at
  3343.      the Editor's request only 2 of the 12 available ASCII pictures have
  3344.      been included.  The full set of 12 may be downloaded as ASCIIPIC.ZIP
  3345.      on the Crescent Support BBS at no cost.  If calling Crescent is
  3346.      inconvenient, the same set is available from the author on a 360K
  3347.      diskette for $3.00 to cover the cost of materials, postage and
  3348.      handling.
  3349.      
  3350.         I find ASCII art to be quaint and entertaining. If you come across
  3351.      or create any good ASCII pictures I'd appreciate your sending me a
  3352.      copy.
  3353.      
  3354.      Enjoy!
  3355.      
  3356.      *********************************************************************
  3357.      Charles Graham is a division head for a local government agency in St.
  3358.      Louis County, Missouri.  He also teaches QuickBASIC part time at a
  3359.      local community college.  He is the author of several shareware
  3360.      products including MOVIES . ON . LINE and Quick Dial.  He can be
  3361.      contacted at Post Office Box 58634, St. Louis, MO 63158, and on the
  3362.      National QuickBASIC Conference.
  3363.      *********************************************************************
  3364.      
  3365.  
  3366.  
  3367.  
  3368.  
  3369.  
  3370.  
  3371.  
  3372.  
  3373.  
  3374.  
  3375.  
  3376.  
  3377.  
  3378.  
  3379.  
  3380.      The QBNews                                                     Page 56
  3381.      Volume  2, Number  2                                      May 31, 1991
  3382.  
  3383.  
  3384.  
  3385.      ----------------------------------------------------------------------
  3386.                     Q B N e w s   S p e c i a l   R e p o r t
  3387.      ----------------------------------------------------------------------
  3388.  
  3389.      Special Preview of Visual Basic by Dave Cleary
  3390.        
  3391.         On May 20, 1991, Microsoft  announced the long anticipated  Visual
  3392.      Basic Windows  Development  Environment. Steve  Gibson  calls  it the
  3393.      "masterstroke of  the decade".  Stewart Alsop  calls it  "the perfect
  3394.      user programming environment -  for the 1990s".  But what does Visual
  3395.      Basic mean to me and you, the QuickBASIC developer?
  3396.         First, I'm going to start out telling you what Visual Basic is and
  3397.      isn't. Visual Basic isn't an upgrade to QuickBASIC. VB is a whole new
  3398.      product that requires all  new tools and  a totally different thought
  3399.      process in  regards to designing  your programs.  This is  because VB
  3400.      creates Microsoft Windows  programs and  writing Windows  programs is
  3401.      like write for a  whole new operating system.  Instead of calling DOS
  3402.      to perform needed  functions, you  call the  Windows API (Application
  3403.      Programming Interface).
  3404.         Windows is  an  Event  Driven environment.  This  is  why  writing
  3405.      programs in VB requires a different  thought process. When you create
  3406.      a VB program,  the majority  of your subs  and functions  will not be
  3407.      invoked by  you.  Instead,  Windows  will  invoke  them  depending on
  3408.      actions performed by  the user. We  will go deeper  into event driven
  3409.      programming later in the article.
  3410.      
  3411.         The  Visual  Basic  environment  isn't  as  sophisticated  as  the
  3412.      QuickBASIC environment. Although VB does contain many features of the
  3413.      QB environment, some are  left out. The biggest  omission is the fact
  3414.      you can not set up a watchpoint on a variable. Instead, VB allows you
  3415.      to go the an immediate window to view or set variable values. VB also
  3416.      lets you insert Debug.Print statements  throughout your code to print
  3417.      values to your immediate window as  the program runs. VB does contain
  3418.      QB's threaded p-code  technology allowing you  to change  code on the
  3419.      fly without  a recompile.  The  amusing thing  is  that C  and Pascal
  3420.      programmers who try  VB think it  is the greatest  thing since sliced
  3421.      bread. I  feel, however, that  QB programmers  who try  VB will  be a
  3422.      little disappointed - at first.
  3423.         VB is probably the easiest and most productive Windows development
  3424.      environment around. For instance, I can create a Windows file manager
  3425.      that contains a drive  list, a directory  list, and a  file list, and
  3426.      give the user three push buttons with the choice of editing, running,
  3427.      or deleting the selected  file. All this  can be done  with about ten
  3428.      lines of  code.  Of  course,  creating  sophisticated  programs still
  3429.      require a good amount of work and skill by the programmer.
  3430.      
  3431.         Creating programs with VB is a two step process. The first step is
  3432.      to create your  user interface.  This is  done with VB's  visual form
  3433.      designer and a collection of controls. A  control is an object like a
  3434.      push button, a  text box,  or a  timer event.  VB comes with  15 such
  3435.      controls, but VB also lets you  add custom controls. This effectively
  3436.      lets you extend the  VB environment. To create  a custom control, you
  3437.      need to use either  C or ASM  and the Windows  SDK. However, numerous
  3438.      third party vendors will be selling libraries of custom controls.
  3439.      
  3440.      The QBNews                                                     Page 57
  3441.      Volume  2, Number  2                                      May 31, 1991
  3442.  
  3443.         A control  has properties,  events and  methods. A  property is  a
  3444.      physical characteristic of the  control. For instance,  the text in a
  3445.      push button is a property of that control. You are allowed to set and
  3446.      read properties of controls  when you create  them (design time), and
  3447.      when you execute your program (run time).
  3448.         After you are down drawing your  user interface a setting up  your
  3449.      default control properties,  you are ready  to start  coding. The big
  3450.      difference is  that  most of  your  code  will be  associated  with a
  3451.      control event. An event is basically an action by the user that has a
  3452.      subprogram associated with  it. This is  how you  program for Windows
  3453.      event driven environment. For  instance, when you  draw a push button
  3454.      on the screen,  certain events are  associated with it.  One of these
  3455.      events is when  the user  clicks the  button. VB creates  a procedure
  3456.      called Command1_Click.  Command1 is  the  default name  given  to the
  3457.      first push button  you draw,  but you can  change it  to whatever you
  3458.      like by setting its control  name property. The code  you put in this
  3459.      sub is executed every time a user clicks the button.
  3460.         Finally, controls have methods associated with them. A  method can
  3461.      be  thought  of as  an  executable  statement  of  the  control.  For
  3462.      instance, VB has a List Box control. You add items to the list box by
  3463.      using the AddItem method.
  3464.         If you  aren't totally  confused by  now, then  I'm suprised.  The
  3465.      above is not meant to  teach you how to program  in VB, but rather to
  3466.      show you how different it is. This  is why I feel porting existing QB
  3467.      programs over to VB  will be difficult  at best. Now  the question is
  3468.      "Should I buy VB?". If  you plan on doing  any Windows development at
  3469.      all, then  the answer  is  a resounding  yes.  If you  don't  plan on
  3470.      writing any Windows programs, but use  Windows as your environment of
  3471.      choice, then the answer is  still a resounding yes.  You will be able
  3472.      to create  those little  utilities you  wished  you had,  but haven't
  3473.      found yet and you will be  able to do it in  short order. If you hate
  3474.      Windows, or don't own  an 80286 or 80386  machine, then don't bother.
  3475.      You won't be able to use VB anyway.
  3476.         Registered users of any  Microsoft BASIC product  can buy VB  from
  3477.      Microsoft for $99,  half off  list price.  You can call  Microsoft at
  3478.      1-800-426-9400 or wait for a  coupon to appear in  your mail. Also, I
  3479.      have started a Windows  BASIC conference on  Fidonet. This conference
  3480.      is for the  discussion of  all Windows  BASIC products, not  just VB.
  3481.      Sysops interested in linking up to  this conference should contact me
  3482.      at 1:141/777. Also, if you are interested in checking out some actual
  3483.      VB applications, you can give my BBS a call at 203-426-5958.
  3484.      
  3485.      *********************************************************************
  3486.      Dave Cleary is an  electronics engineer for  Vectron Labs in Norwalk,
  3487.      CT. Besides being a Visual Basic beta tester, Dave is also the author
  3488.      of  Crescent  Software's  PDQComm  and   is  the  publisher  of  this
  3489.      newsletter. He  can  be  contacted on  Compuserve  at  76510,1725, on
  3490.      Prodigy at HSRW18A, and on Fidonet at 1:141/777.
  3491.      *********************************************************************
  3492.      
  3493.  
  3494.  
  3495.  
  3496.  
  3497.      The QBNews                                                     Page 58
  3498.  
  3499.  
  3500.      ----------------------------------------------------------------------
  3501.                                       E O F
  3502.      ----------------------------------------------------------------------
  3503.  
  3504.      Receiving The QBNews
  3505.      
  3506.           The  QBNews is distributed mainly through BBS systems around  the
  3507.      world.  Some  of  the networks it gets  distributed  through  are  SDS
  3508.      (Software   Distribution   System) and  PDN  (Programmers Distribution
  3509.      Network). Ask the  sysop of your  local  board about these networks to
  3510.      see if there is a  node  in your area.
  3511.      
  3512.           The  QBNews  can  also  be found  on  CompuServe  in  the  MSLang
  3513.      (Microsoft  Language)  forum. It can be found in file area 1 or  2  of
  3514.      that  forum. Just search for the keyword QBNEWS. The QBNews will  also
  3515.      be available on PC-Link. I send them to Steve Craver, who is the BASIC
  3516.      Programming  Forum Host on PC-LINK and he will make them available.  I
  3517.      would appreciate anybody who could upload The QBNews to other services
  3518.      such as GENIE since I don't have access to these.
  3519.      
  3520.           I  have also set up a high speed distribution network for  people
  3521.      who  would  like to download The QBNews at 9600  baud.  The  following
  3522.      boards allow first time callers download privileges also. They are:
  3523.      
  3524.          Name           Sysop       Location       Number         Node #
  3525.      ---------------------------------------------------------------------
  3526.      
  3527.      Treasure Island  Don Dawson    Danbury, CT    203-791-8532   1:141/730
  3528.      
  3529.      Gulf Coast BBS   Jim Brewer New PortRichey,FL 813-856-7926   1:3619/20
  3530.      
  3531.      221B Baker St.   James Young   Panama City,FL 904-871-6536   1:3608/1
  3532.      
  3533.      EMC/80           Jim Harre     St. Louis, MO  314-843-0001   1:100/555
  3534.      
  3535.      Apple Capitol BBS Bob Finley   Wenatchee, WA  509-663-3618   1:344/61
  3536.      
  3537.      
  3538.           Finally, you can download The QBNews from these vendors BBS's:
  3539.      
  3540.      The Crescent Software Support BBS   203-426-5958
  3541.      
  3542.      The Microhelp BUG BBS               404-552-0567
  3543.                                          404-594-9625
  3544.      
  3545.      
  3546.      You do not have to be a customer of these vendors in order to download
  3547.      The  QBNews, but the Microhelp BBS only allows non-members 15  minutes
  3548.      of time per call.
  3549.      
  3550.         If you would like to receive The QBNews on disk, I offer a yearly
  3551.      subscription for $15.00. This includes four disks containing each
  3552.      issue as it is published. If you would like a disk with all the back
  3553.      issues of The QBNews, please enclose an additional $5.00. The pricing
  3554.      
  3555.      The QBNews                                                     Page 59
  3556.      Volume  2, Number  2                                      May 31, 1991
  3557.  
  3558.      structure is as follows:
  3559.      
  3560.      Base Price for 1 Year -       $15.00
  3561.      Disk with Back Issues -        $5.00
  3562.      3.5" disk surcharge -          $5.00
  3563.      Canada and Mexico surcharge -  $5.00
  3564.      All other foreign orders -    $10.00
  3565.      
  3566.           The  base price includes 5.25" 360k disks. Send a check or  money
  3567.      order in U.S. funds to:
  3568.      
  3569.           The QBNews
  3570.           P.O. Box 507
  3571.           Sandy Hook, CT 06482
  3572.      
  3573.           Please  be  sure  to specify what archive format  you  want.  The
  3574.      QBNews normally uses PKZip as it's archiver.
  3575.      ----------------------------------------------------------------------
  3576.  
  3577.      Submitting Articles to The QBNews
  3578.      
  3579.           The QBNews relies on it's readers to submit articles. If you  are
  3580.      interested in submitting an article, please send a disk of Ascii  text
  3581.      of no more than 70 characters per line to:
  3582.      
  3583.           The QBNews
  3584.           P.O. Box 507
  3585.           Sandy Hook, CT 06482
  3586.      
  3587.      Articles can also be submitted via E-Mail. Send them via Compuserve to
  3588.      76510,1725 or via FidoNet to 1:141/777. I can be reached at the  above
  3589.      addresses as well as on Prodigy as HSRW18A.
  3590.      
  3591.  
  3592.  
  3593.  
  3594.  
  3595.  
  3596.  
  3597.  
  3598.  
  3599.  
  3600.  
  3601.  
  3602.  
  3603.  
  3604.  
  3605.  
  3606.  
  3607.  
  3608.  
  3609.  
  3610.  
  3611.  
  3612.  
  3613.  
  3614.      The QBNews                                                     Page 60
  3615.  
  3616.